What goes into a JWT refresh_token?
Asked Answered
A

1

1

I built some JWT middleware for my Asp.net Core REST service based on some examples I found online. I get that the response looks like:

{
   "access_token":"...",
   "expires_in":3600,
   "refresh_token":"???",
   "token_type": "Bearer",
}

I understand how to create access_token:

Claim[] claims = new Claim[]
{
    new Claim(JwtRegisteredClaimNames.Sub, strUsername),
    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
    new Claim(JwtRegisteredClaimNames.Iat, dtNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
};

JwtSecurityToken jwtAccess = new JwtSecurityToken(_options.Issuer, _options.Audience, claims, dtNow.DateTime,
                                                  dtNow.DateTime.Add(_options.AccessTokenExpiration), _options.SigningCredentials);

The question is how do I create refresh_token? I have searched high and low and can't find much documentation on it. Basically all every reference says is "its a token stored in a database with a longer TTL that you can create a new access_token from".

So is a refresh_token the same exact thing as access_token with just the longer TTL and the additional step that its validated against the database?

Some of the example JWT responses I've seen seem like the refresh_token is much shorter. My access_token is signed with a certificate using RSA515, so the string is kinda long...

Alteration answered 16/9, 2016 at 3:24 Comment(9)
Now personally my refresh tokens are just JWTs with longer TTL and a little more information that help me verify the resource owner. It could be a simple GUID used to map user to token where the expiry time is also stored in the database along with the token.Flesh
Take a look at the following article from Auth0 and it support links auth0.com/docs/tokens/refresh_tokenFlesh
@Nkosi, in that link, the refresh_token is really short.Alteration
@Nkosi, I would think a GUID is pretty insecure.Alteration
Which is why I usually tend to use another JWT for the refresh token. It may seem redundant. but i store a Guid within the JWT to act as an identifier check the database for that along with some other identifiable information for the client. I would say it is more a matter of preferenceFlesh
@Nkosi, So, in my case, as I said, I am using a cert to sign with RSA512, so my access_token is 1K. You have a 1K token for the access and the refresh?Alteration
Well then in that case a decision would have to be made concerning the length of the payload. I would go with a shorter encoding. It is a matter if preference. the main thing is about making sure that the refresh token is safely stored and not leaked.Flesh
@Nkosi, if I may ask, do you use a cert? Or simple password? to sign your JWT? I was using a simple password before, but I changed it to a cert... signing with a cert may be too cumbersome though due to payload size.Alteration
I've used both for various projects depending on requirements and limitations. payload size was an issue with certs so in those cases we used shorter/simpler refresh tokens.Flesh
F
1

Now personally my refresh tokens are just JWTs with longer TTL and a little more information that help me verify the resource owner.

Take a look at the following article from Auth0 and it support links

https://auth0.com/docs/tokens/refresh_token

It could even be a simple GUID used to map user/client to token where the expiry time is also stored in the database along with the token.

The following example is from the link sited above where they use what looks like a Guid for the refresh token.

So, for instance, assuming there is a user 'test' with password 'test' and a client 'testclient' with a client secret 'secret', one could request a new access token/refresh token pair as follows:

$ curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'grant_type=password&username=test&password=test' localhost:3000/oauth/token

{
    "token_type":"bearer",
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI1NDMsImV4cCI6MTQ0NDI2MjU2M30.MldruS1PvZaRZIJR4legQaauQ3_DYKxxP2rFnD37Ip4",
    "expires_in":20,
    "refresh_token":"fdb8fdbecf1d03ce5e6125c067733c0d51de209c"
}

Once their token has expired they make a call passing the refresh token to get a new access token.

Now we can use the refresh token to get a new access token by hitting the token endpoint like so:

curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'refresh_token=fdb8fdbecf1d03ce5e6125c067733c0d51de209c&grant_type=refresh_token' localhost:3000/oauth/token

{
    "token_type":"bearer",
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
    "expires_in":20,
    "refresh_token":"7fd15938c823cf58e78019bea2af142f9449696a"
}

Security Considerations

Refresh Tokens are long-lived. This means when a client gets one from a server, this token must be stored securely to keep it from being used by potential attackers, for this reason it is not safe to store them in the browser. If a Refresh Token is leaked, it may be used to obtain new Access Tokens (and access protected resources) until it is either blacklisted or it expires (which may take a long time). Refresh Tokens must be issued to a single authenticated client to prevent use of leaked tokens by other parties. Access Tokens must also be kept secret, but due to its shorter life, security considerations are less critical.

Flesh answered 16/9, 2016 at 3:59 Comment(3)
I know that. the examples were to show that it doesn't have to be a JWTFlesh
Oh, I see, ok, sorry :-)Lubalubba
No problem. easy to misunderstand. I could have probably worded it better.Flesh

© 2022 - 2024 — McMap. All rights reserved.