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 (18)
You can use
options.EnableLogoutEndpointPassthrough();
{
"error": "invalid_grant",
"error_description": "The specified token is not a refresh token.",
"error_uri": "documentation.openiddict.com/error..."
}
give me solution of this error
Hi Ankush,
The solution in your case is most likely the same one that was required by most here who had the same issue: When you copy+paste the Refresh Token (or any token) from the Postman user interface, it also adds an extra paragraph character in the end of your token. So when you paste your token, press the Backspace key once to delete it.
If that does not work (unlikely), then your token is either the wrong one like Oleg suggested, or it even expired, or what was pasted/written is simply something else entirely.
I suppose you send an access token instead of a refresh token
you need enable "offline_access" scope to get refresh token
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
Please provide right grant_type
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
Yep! I'm sure this caught a lot of people.
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
I have a question regarding calling Authorization Server from a different .NET Framework web forms application or Asp.net Core client application, I tried what you have suggested in the blog, I am able to generate authorization code and iss attached to query string. Do i need to send post request to token end point to get the access token or will it automatically execute token end point? I have no clue how it works from a client web applications. I tried to use some OpenID Microsoft Namespaces to connect to the Authorization Server and I am receiving an error. Could you please guide me to proceed further on this.
InvalidOperationException: Cannot redirect to the authorization endpoint, the configuration may be missing or invalid.
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority
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?