TransWikia.com

get signature from TokenValidatedContext

Stack Overflow Asked by Olaf Svenson on September 8, 2020

I’m using the Microsoft.AspNetCore.Authentication.JwtBearer and System.IdentityModel.Tokens.Jwt packages for my .NET Core project.

When configuring the services I’m adding logic to the OnTokenValidated event.

    services
        .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(jwtBearerOptions =>
        {
            // ... set TokenValidationParameters ...

            jwtBearerOptions.Events = new JwtBearerEvents()
            {
                OnTokenValidated = (tokenValidatedContext) => 
                {
                    JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
                    string tokenWithoutSignature = jwtSecurityTokenHandler.WriteToken(tokenValidatedContext.SecurityToken);

                    // ... full token from request? ...
                }
            };
        });

Since I know the context only returns me the token without the signature I would like to know how I can

  • either get the full token with signature
  • or the signature additionally to add it to the tokenWithoutSignature string

If this is not possible:

I’m generating new tokens this way

public string GenerateAccessToken(IDictionary<string, object> payload)
{
    SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(Convert.FromBase64String("secret from config"));

    SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
    {
        Claims = payload,
        Expires = DateTime.Now, // value from config
        SigningCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256Signature)
    };

    JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
    SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
    string token = tokenHandler.WriteToken(securityToken);

    return token;
}

Maybe I can either retrieve

  • the token string without the signature
  • only the signature

within this method?


If nothing works:

Since I kow a bearer token always contains three parts like

header.payload.signature

I could split the string segments to an array, take the first and second element from the array and create a new string of

firstString + . + secondString

That should give me the token without the signature. Are there any better ideas to cut off the signature from a full token?


Why do I want to achieve this?

This question is based on this one

Security token from TokenValidatedContext from the OnTokenValidated event listener is missing last string segment

I’m working with access and refresh tokens. During validation, I have to compare the token from the request with the token from the database. The token in the database contains the signature too. So I’m facing the same problem as linked above.

That’s why I thought about multiple solutions and wrote them down here. If the TokenValidatedContext is not able to return me the signature it seems I have to store the JWT to the database without the signature. And also for this case, I need to separate the signature from the generated JWT.

Without using refresh tokens I only store the maximum session lifetime of a user to the database. The flow is based on this idea

Only store the time of the JWT with the highest lifetime to the database instead of the whole JWT

With using refresh tokens I came up with the following flow. Since you know that the OnTokenValidated handles the validation logic the following logic is additional. I have a database table with

username | access_token | refresh_token | refresh_token_expires_at

and the primary key is a composite key of username + access_token. Refresh tokens are just some random strings generated like so

public string GenerateRefreshToken()
{
    var randomNumber = new byte[32];

    using (var rng = RandomNumberGenerator.Create())
    {
        rng.GetBytes(randomNumber);

        return Convert.ToBase64String(randomNumber);
    }
}

and that’s why I’m storing an additional expiration date to it. It should be able to expire after some time.

  • Signing in

    Store the generated access and refresh token and its expiration time for a user to the database. Either store the full access token or the access token without signature to the database (depends on the solution of this question).

  • Hitting a protected endpoint

    Check if that access token for that user exists in the database.

  • Hitting the refresh endpoint

    Check if the database refresh token has expired. If not, compare this one with the refresh token from the request. If everything is fine, remove the old access and refresh token from the database and store the new generated access and refresh token to the database.

  • Signing out

    Remove that access and its connected refresh token from the database.

2 Answers

I don't quite understand why you do all this, but if all you need is the original token, you can use one of these:

o.Events = new JwtBearerEvents
{
    OnTokenValidated = (context) =>
    {
        var securityToken = (System.IdentityModel.Tokens.Jwt.JwtSecurityToken)context.SecurityToken;
        var token = securityToken.RawData; // "ey...."
        var tokenHeader = securityToken.RawHeader; // "ey...."
        var tokenPayload = securityToken.RawPayload; // "ey...."
        var tokenSignatur = securityToken.RawSignature; // "ey...."
        var fullBearerHeader = context.Request.Headers["Authorization"]; // "Bearer ey..."
        return Task.CompletedTask;
    }
};

You probably want to make the code a bit more safe with regards to type casting etc., but it should give you the token.

Correct answer by Alex AIT on September 8, 2020

Why do you want to manipulate the token? If it is just to Validate the token you can use below code.

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)    
.AddJwtBearer(options =>    
{    
    options.TokenValidationParameters = new TokenValidationParameters    
    {    
        ValidateIssuer = true,    
        ValidateAudience = true,    
        ValidateLifetime = true,    
        ValidateIssuerSigningKey = true,    
        //ValidIssuer = Configuration["Issuer"],    
        //ValidAudience = Configuration["Audience"],    
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Key"]))    
    };    
});    

and

public void Configure(IApplicationBuilder app, IHostingEnvironment env)    
{    
    app.UseAuthentication();    
    app.UseMvc();    
} 

Answered by Ansil F on September 8, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP