asp.net-coreasp.net-core-webapi.net-8.0asp.net-core-identity

.NET 8 Microsoft Identity saving Access and Refresh tokens to database on user sign in and token refresh


I've been investigating the new .NET 8 Web APIs and identity to see how they work as I'm looking to upgrade from an existing .NET 4.8 project.

From what I can see, the login endpoint provides the user with an access token and a refresh token which I want to use for a web app and the default method makes it very easy to get. I am using Microsoft identities and NOT JWT tokens.

However, I'm wanting to save the initial login details with the tokens to save it onto my database so I can control access of the tokens.

For example,

  1. User logins and receives access / refresh tokens
  2. Save this information on the database
  3. When user uses refresh token to regenerate auth
  4. Check database to see if refresh token is valid.
  5. If yes, generate a new token, mark the current database record as invalid now, save the new token info.
  6. If no, then show 401 unauthorised.
  7. If user calls the login endpoint again (while the current auth is valid), invalidate the old login (so the bearer token doesn't work and refresh token can't be used to extend).

Similarly, I want to have a way to check if the bearer token in the API calls are valid for use by checking the database.

What I've done so far is to override the default IdentityApiEndpointRouteBuilderExtensions so I can see how the login and refresh endpoints are working.

On the routeGroup.MapPost("/login"....) method, I see that this piece of code is performing the logging in:

var result = await signInManager.PasswordSignInAsync(login.Email, login.Password, isPersistent, lockoutOnFailure: true);

This returns a SignInObject which doesn't provide any details of the tokens that's just been generated.

On the routeGroup.MapPost("/refresh"...) method, I see this line:

var refreshTokenProtector = bearerTokenOptions.Get(IdentityConstants.BearerScheme).RefreshTokenProtector;

This seems to get the refresh token which I could potentially use to check with my database and check if it's valid before proceeding any further (haven't tried it yet but will try it soon).

I am unable to find much details regarding modifying the existing identity methods so what is the best way to retrieve the access / refresh tokens on the login and refresh - or any other overridden method - so I can save this into the database for checking future requests?

EDIT: on the /login method, it states this as an official comment:

// The signInManager already produced the needed response in the form of a cookie or bearer token.

return TypedResults.Empty;

How can I get the tokens from here?


Solution

  • After a lot of investigating, I've come to the conclusion that it is not possible to retrieve the access token and refresh token from the login endpoint. (If this is incorrect, please feel free to write a new answer!)

    What I've opted to do instead is, straight after logging in, use the bearer token to make another call to the API by passing in the access and refresh tokens in the body.

    Not sure if this is the best way or the cleanest way to do it, but this provides me with the solution I need to save details about the access tokens on my DB so I can control individual bearer tokens as needed.

    NOTE: I've also considered what browsermator mentioned in my question comment [the whole point of access token is to not hit the DB (or use a session variable) when verifying the session] - and this seems like a fair point.

    With this in mind, I also created a middleware which checks the user object to see if their account is valid for use (since I retrieve the user object anyway) and just disable their access using the user table instead of the tokens.