You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Which version of Duende.AccessTokenManagement are you using?
We are currently not. We are using .Net Framework, which the library doesn't support. The code for review below achieves a similar goal, hence why I logged it under this.
Which version of .NET are you using?
.Net Framework 4.8
This isn't a bug more of a question / code review
We have a .Net Framework 4.8 application (APP) which authentications to Identity server 6.10.3, which works perfectly. This application then makes calls to another application (also authenticated via the same SSO) via an API call (API).
Over time, the access token needs to be refreshed in the APP to be able to continue talking to the API. This requires a refreshing of the token periodically. Which there doesn't seem to be a pre built component for.
Below is my implementation, which works correctly, but being a bit paranoid about security. I thought it might be wise to have the experts run an eye over it and to share it with other developers who might be in the same situation.
The code below fetches the access token from OWIN, then checks the expiry, if the token is expired. The system then requests a new token and updates the users authentication cookie (with updated access_token and refresh token). This caches the updated tokens for future requests. If the token hasn't expired, it is returned directly.
As the experts, can you see any issues with the below?
/// <summary>/// Get and optionally refresh the JWT access token for the currently logged-in user provided by the SSO system./// </summary>/// <param name="context">The <see cref="HttpContext"/> to get the token from.</param>/// <returns>A string containing the JWT token.</returns>publicstaticasyncTask<string>GetAccessToken(thisHttpContextcontext){if(context==null)thrownewArgumentNullException(nameof(context));varauthenticateResult=awaitcontext.GetOwinContext().Authentication.AuthenticateAsync("cookie").ConfigureAwait(false);if(authenticateResult?.Properties==null||authenticateResult.Identity==null){thrownewInvalidOperationException("Authentication result or its properties are null.");}if(!authenticateResult.Properties.Dictionary.TryGetValue("access_token",outvartoken)||string.IsNullOrEmpty(token)){thrownewInvalidOperationException("Access token is missing.");}vartokenHandler=newJwtSecurityTokenHandler();vardecodedToken=tokenHandler.ReadJwtToken(token);// Do we need to refresh the token, if not return it.if(decodedToken.ValidTo>=DateTime.UtcNow){returntoken;}// Otherwise, renew the token.varssoAuthority=ConfigurationManager.AppSettings["SsoAuthority"];varssoClientId=ConfigurationManager.AppSettings["SsoClientId"];varssoSecret=ConfigurationManager.AppSettings["SsoSecret"];if(string.IsNullOrEmpty(ssoAuthority)||string.IsNullOrEmpty(ssoClientId)||string.IsNullOrEmpty(ssoSecret)){thrownewInvalidOperationException("SSO configuration is missing or invalid.");}using(varclient=newHttpClient()){try{// Fetch configuration from the SSO.vardisco=awaitclient.GetDiscoveryDocumentAsync(ssoAuthority).ConfigureAwait(false);if(disco.IsError){thrownewInvalidOperationException($"Error fetching discovery document from {ssoAuthority}.");}using(vartokenRefreshRequest=newRefreshTokenRequest()){// Create token request.tokenRefreshRequest.Address=disco.TokenEndpoint;tokenRefreshRequest.ClientId=ssoClientId;tokenRefreshRequest.ClientSecret=ssoSecret;tokenRefreshRequest.RefreshToken=authenticateResult.Properties.Dictionary["refresh_token"];// Get refreshed tokens from the SSO.vartokenRefreshResponse=awaitclient.RequestRefreshTokenAsync(tokenRefreshRequest).ConfigureAwait(false);if(tokenRefreshResponse.IsError){thrownewInvalidOperationException("Error refreshing token.");}// Copy the claims, without the access_token and refresh_token.varupdatedClaims=authenticateResult.Identity.Claims.Where(t =>t.Type!="access_token"&&t.Type!="refresh_token").ToList();// Add updated token back in.updatedClaims.Add(newSystem.Security.Claims.Claim("access_token",tokenRefreshResponse.AccessToken));updatedClaims.Add(newSystem.Security.Claims.Claim("refresh_token",tokenRefreshResponse.RefreshToken));// Create new Identity.varupdatedIdentity=newClaimsIdentity(updatedClaims,authenticateResult.Identity.AuthenticationType);// Update the token in the properties.varupdateProperties=authenticateResult.Properties;updateProperties.Dictionary["access_token"]=tokenRefreshResponse.AccessToken;updateProperties.Dictionary["refresh_token"]=tokenRefreshResponse.RefreshToken;// Update the auth with new access details.context.GetOwinContext().Authentication.SignIn(updateProperties,updatedIdentity);// Assign the updated token for return.token=tokenRefreshResponse.AccessToken;}}catch(Exceptionex){// Log the exception (consider using a logging framework)thrownewInvalidOperationException("An error occurred while refreshing the token.",ex);}}returntoken;}
The text was updated successfully, but these errors were encountered:
I think this might not be the right place to ask this since it's not about any of our products and we can't accept any responsibility for the correctness of your code nor support it, but I can can give you a few hints:
The client (where this code is running) isn't allowed to read the access token. It is just for the API. The request coming back from the identity provider that contains the access token has a JSON structure that contains the expiration information. Use that instead.
It seems like access and refresh token are added both to the ClaimsIdentity and the authentication properties.
Which version of Duende.AccessTokenManagement are you using?
We are currently not. We are using .Net Framework, which the library doesn't support. The code for review below achieves a similar goal, hence why I logged it under this.
Which version of .NET are you using?
.Net Framework 4.8
This isn't a bug more of a question / code review
We have a .Net Framework 4.8 application (APP) which authentications to Identity server 6.10.3, which works perfectly. This application then makes calls to another application (also authenticated via the same SSO) via an API call (API).
Over time, the access token needs to be refreshed in the APP to be able to continue talking to the API. This requires a refreshing of the token periodically. Which there doesn't seem to be a pre built component for.
Below is my implementation, which works correctly, but being a bit paranoid about security. I thought it might be wise to have the experts run an eye over it and to share it with other developers who might be in the same situation.
The code below fetches the access token from OWIN, then checks the expiry, if the token is expired. The system then requests a new token and updates the users authentication cookie (with updated access_token and refresh token). This caches the updated tokens for future requests. If the token hasn't expired, it is returned directly.
As the experts, can you see any issues with the below?
The text was updated successfully, but these errors were encountered: