Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I exchange my refresh token for a new access token?

Before authorization expires I want to get a new access token in exchange for my refresh token.

Right now I get a cookie which I believe has all the tokens I've asked for (I do not know how to inspect the contents of this cookie).

My client is able to sign in and call my REST API using ajax, however when that first authorization expires, naturally the API calls no longer work.

I have a .NET web application which consumes its own REST API. The API is a part of the same project. It does not have its own startup configuration.

Here's an idea of what it looks like:

  • MyProject
    • MyApiFolder
      • FirstController.cs
      • SecondController.cs
      • ...
    • AppStartFolder
      • Startup.cs
      • RouteConfig.cs
      • ...
    • Views
      • ...
    • Controllers
      • ...
    • Scripts
      • ...
    • Web.config
    • ...

I am using Identity Server 4, with Owin middleware. My MVC client is able to sign in, and able to communicate with this API until the authorization expires.

Here is my hybrid flow client:

using IdentityModel.Client;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

namespace Cts.HomeService.Web.App_Start
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var identityServerSection = (IdentityServerSectionHandler)System.Configuration.ConfigurationManager.GetSection("identityserversection");

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "Cookies",
                CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager()
            });


            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = "localTestClient",
                Authority = "http://localhost:5000",
                RedirectUri = identityServerSection.Identity.RedirectUri,
                Scope = "openid profile offline_access",
                ResponseType = "code id_token",
                RequireHttpsMetadata = false,
                PostLogoutRedirectUri = identityServerSection.Identity.RedirectUri,

                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "role",
                },
                SignInAsAuthenticationType = "Cookies",
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthorizationCodeReceived = async n =>
                    {
                        var tokenClient = new TokenClient(
                            "http://localhost:5000/connect/token",
                            "localTestClient",
                            "");

                        var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(
                            n.Code, n.RedirectUri);

                        if (tokenResponse.IsError)
                        {
                            throw new Exception(tokenResponse.Error);
                        }

                        // use the access token to retrieve claims from userinfo
                        var userInfoClient = new UserInfoClient(
                            "http://localhost:5000/connect/userinfo");

                        var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);

                        // create new identity
                        var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
                        id.AddClaims(userInfoResponse.Claims);

                        id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
                        id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
                        id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
                        id.AddClaim(new Claim("id_token", tokenResponse.IdentityToken));
                        id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));

                        n.AuthenticationTicket = new AuthenticationTicket(
                            new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
                            n.AuthenticationTicket.Properties);
                    },

                    RedirectToIdentityProvider = n =>
                    {
                        {
                            // if signing out, add the id_token_hint
                            if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                            {
                                var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                                if (idTokenHint != null)
                                {
                                    n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                                }
                            }
                            return Task.FromResult(0);
                        }
                    }
                }
            });
        }
    }
}
  1. How do I make the client exchange his access token for a refresh token?
  2. How do I know what is stored in my ASP.NET Cookie?
like image 677
Pointo Senshi Avatar asked Nov 19 '25 02:11

Pointo Senshi


1 Answers

Get the refresh token from the cookie using extension methods defined in Microsoft.AspNetCore.Authentication:

var refreshToken = await HttpContext.GetTokenAsync("refresh_token");

Use IdentityModel to exchange refresh token for an access token:

var client = new HttpClient();

var response = await client.RequestRefreshTokenAsync(new RefreshTokenRequest
{
    Address = "http://localhost:5000/connect/token",

    ClientId = "localTestClient",
    ClientSecret = "secret",

    RefreshToken = refreshToken
});

var accessToken = response.AccessToken
like image 51
Richard Avatar answered Nov 21 '25 14:11

Richard