OpenIdDict Degraded Mode with Refresh token

Viewed 27

We are using the OpenIddict degraded mode to wrap around another login type. This works. However at first I didn't get the refresh token to work. I didn't find any example where the refresh token was implemented in combination with the degraded mode. We found a way to make it work, but it feels hacky. The part about the refresh flow is below:

options.AddEventHandler<ValidateTokenContext>(builder =>
builder.UseInlineHandler(async context =>
{
    if (context.Request.IsRefreshTokenGrantType())
    {
        //Fetching the user principal based on the provided refresh token
        var req = new GetRefreshTokenRequest { RefreshToken = context.Request.RefreshToken, ClientID = context.Request.ClientId };

        var newRefreshToken = await _mediator.Send(req);
        if (newRefreshToken != null)
        {
            var user = await _mediator.Send(new GetUserByEmailRequest { Email = newRefreshToken.Email });

            //We have to provide a principal, if it was a valid refresh token
            context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
                .SetTokenType(TokenTypeHints.RefreshToken)
                .SetClaim(Claims.Subject, user.Email);

            //A bit hacky, but we pass through the refresh token
            //This way HandleTokenRequestContext won't need to fetch it again
            context.Request.RefreshToken = newRefreshToken.Token;
            return;
        }
        else
        {
            context.Reject(
                error: Errors.InvalidRequest,
                description: "The provided refreshtoken is not valid."
                );
            return;
        }
    }
    return;
}).SetOrder(Protection.ValidateIdentityModelToken.Descriptor.Order - 500)
);

options.AddEventHandler<HandleTokenRequestContext>(builder =>
        builder.UseInlineHandler(async context =>
        {
            var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType);
            identity.AddClaim(OpenIddictConstants.Claims.Subject, context.ClientId);

            if (context.Request.IsRefreshTokenGrantType())
            {
                // Retrieve the claims principal stored in the refresh token.
                //ValidateTokenContext already fetched a new refreshtoken and stored it in the request, we now add it to the response
                context.Parameters[OpenIddictServerAspNetCoreConstants.Tokens.RefreshToken] = context.Request.RefreshToken;
            }
            else
            {
                //get first refresh token
                var firstRefreshToken = new PBKDF2().GenerateSalt(1, 32);
                var email = context.Principal.GetClaim(ClaimTypes.Email); 
                await _mediator.Send(new SaveRefreshTokenRequest { Email = email, RefreshToken = firstRefreshToken, ClientId = context.ClientId  });

                context.Parameters[OpenIddictServerAspNetCoreConstants.Tokens.RefreshToken] = firstRefreshToken;
            }

            var cp = new ClaimsPrincipal(identity);
            cp.SetScopes(context.Request.GetScopes());

            context.SignIn(context.Principal);

            return;
        }));

I upgraded to OpenIddict 4.0.0-preview3, to be able to use "context.Parameters". Is there a way to make this work with 3.0? Is there a more standard way to make the refresh work in degraded mode?

0 Answers
Related