This article is part of a series called Setting up an Authorization Server with OpenIddict. The articles in this series will guide you through the process of setting up an OAuth2 + OpenID Connect authorization server on the the ASPNET Core platform using OpenIddict.
- Part I: Introduction
- Part II: Create ASPNET project
- Part III: Client Credentials Flow
- Part IV: Authorization Code Flow
- Part V: OpenID Connect
- Part VI: Refresh tokens
robinvanderknaap
/
authorization-server-openiddict
Authorization Server implemented with OpenIddict.
Access tokens typically have a short lifetime for security reasons. In this part we will enable the usage of refresh tokens. A refresh token allows an application to obtain a new access token without prompting the user.
Enable refresh tokens
First we need to enable the refresh token flow in Startup.cs
:
options
.AllowAuthorizationCodeFlow()
.RequireProofKeyForCodeExchange()
.AllowClientCredentialsFlow()
.AllowRefreshTokenFlow();
In the token endpoint in the AuthorizationController
we need to handle refresh token requests, just like we handled client credentials requests, and requests to exchange authorization codes for access tokens:
[HttpPost("~/connect/token")]
public async Task<IActionResult> Exchange()
{
...
else if (request.IsAuthorizationCodeGrantType())
{
...
}
else if (request.IsRefreshTokenGrantType())
{
// Retrieve the claims principal stored in the refresh token.
claimsPrincipal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;
}
...
}
Basically, we only need to retrieve the ClaimsPrincipal from the refresh token, and sign in again, which will return a new access token.
Finally, we need to allow the client to use refresh tokens:
Permissions =
{
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.GrantTypes.ClientCredentials,
OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
OpenIddictConstants.Permissions.Prefixes.Scope + "api",
OpenIddictConstants.Permissions.ResponseTypes.Code
}
If a client wants to use refresh tokens, it needs to request the offline_access
scope. Just like we requested the openid
scope for identity tokens. Now, if we request a new access token with Postman, we will receive a refresh token together with the access token.
After that, we can use the refresh token to request a new access token with Postman. Send a POST request to /connect/token
with a body containing the client credentials, grant type and of course the refresh token.
In the response you will find a new access token and also a new refresh token. So, refresh tokens are automatically rotated, which is more secure than reusing the same refresh token.
Top comments (12)
You can use
options.EnableLogoutEndpointPassthrough();
this error is thrown for me
{
"error": "invalid_grant",
"error_description": "The specified token is not a refresh token.",
"error_uri": "https://documentation.openiddict.com/errors/ID2007"
}
what should i do to take refresh-token?
i mean , i just sigin in with client-id and client-secret and just take one token. this token should be acess token , then how i get refresh token ?
i found it , i just should add this to my access token request .
scope => api offline_access
Hi, Thanks for simple yes complete and inspiring example.
I've implemented it with Microsoft Identity with ef as persistence. Works fine until I request exchange of refresh token for a new at.
So, I ran author's example from github as reference and got the same result which is:
I checked everything. App registration (permissions) is fine. Grant looks correct. Currently I use postman, but experience the same when using a front-end library (can't say the name right now, but it is used with a React app).
Log shows, that the request was recognised, but then refresh token wasn't recognised as valid by openiddict.
When put to jwt.io, it says an error: "JWT payload is not a valid JSON object. JWT payload must be top level JSON object..."
Actually I can't influent JWT refresh token as it is prepared by the library. Maybe it needs additional configuration?
Any idea what can be done here to fix the problem?
same here , have u found the solution ?
one more thing i noticed when i try to refresh the token from the built in refresh in postman
i think it works
and if i used breakpoints and debugged it actually enters the action of the connect/token end point
although if i used inspect the request after this refresh produces this
meanwhile the post request for the refresh token doesn't enter the action while useing the debugger , but produces this in post man
i guess the request itself has something missing ?
it turned out to be that when i copy the refresh token from the stored token in postman to put it in my post methed it pastes it with an extra new line resulted from an extra /n or /r maybe ,, so after removing it it worked fine ,
also don't forget to update the used tokens (access and refresh) after calling the post method each time
Thanks Robin. I needed to add the following lines, to include the refresh token in the jwt, not sure if it's necessary in your codebase though:
github.com/openiddict/openiddict-s...
Ah, never mind. I see you have it there:
github.com/robinvanderknaap/author...
embassador, with these rocher your spoil us
Great series! Thanks!
Would you make another article on how to leverage custom grants?
How to implement the logout flow, where I need to return a redirect_uri to the client, and also invalidate the id_token?