Access token and Refresh token, approach with golang
Tags: backend, jwt, tokens
Published: 2023-02-08 02:53:34

**_Why login again if you have something that I trust ?_**

When we are dealing with authentication and authorizations in web services, the standard approach is to work with JWT tokens.

A quick recap about JWT **(JSON Web tokens)** is that it basically a secure form to dealing with information exchange and authentication requests between services, having data stored in a JSON format.

However despite the efficiency of the JWT's, it's a good practice to give these tokens a valid time to live, and after this time is over, the token is treated as expired. A normal behaviour when this situation happens is to force the user to login again in the application to get a new token. But to avoid this incovenient step and make it clear as possible to the users, a common approach is to **"refresh"** the old token for a new one, using something that the application is able to **trust**. To use as a trustful artifact for the application's backend, we can use another (guess what...) **JWT TOKEN**.

So, to resume the concert, when the user does the login in the application, the backend responds with two informations, one is the **access-token** (standard nomenclature) a JWT token that will be used to authorize the user on the web services of the app, and the second info is the **refresh-token** (standard nomenclature) a JWT token that will be used to give the user another new token when the actual access-token would expired. _Bellow a image of a request and a response_

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb9yy5qltzjusocill23.png)

**_Proving the authenticity of the access-token (check the payload section, the user's email is the same used to singIn and it's passed the user's id as sub property)_**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahw0ycxthwe5eulbjks7.png)

**_Proving the authenticity of the refresh-token (check the payload section that we only have the user's id as sub)_**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/seaqj5cum20t3ekfbouy.png)


_It is important to notice the usage of the audience (aud) and issuer (iss) claims, because these two informations will be requested on the logic to refresh the token_

## The GOLANG code that makes all the magic

_**Libraries used**_
bcrypt: https://pkg.go.dev/golang.org/x/crypto/bcrypt
golang-jwt: https://github.com/golang-jwt/jwt
Gin (Http framework): https://github.com/gin-gonic/gin

First of all, on this example I wanted to emphasize the implementation of the refresh token and JWT dealing work using the Go language, abstracting the architectural good practices and breaking all the pieces into functions

_The signIn endpoint_


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vm8zi4xpwl1gojwacbr5.png)


In the first part of the code (until line 85) I just parse the request, take the credendials sent by the user, and validate all the information checking if the email provided exists on the database and the password is correct. Bellow a detailed image from the **_FindAndValidateUserCredendials_**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/frjw1seq2o3wr631kk34.png)
So, basically what the code does is query the user using the email information provided as a filter, if the user exists  is proceed to check if the hashing password stored for this user on the database, is matched with the plain text one provided in request. I used the **crypto bcrypt** library in golang to deal with the hashed password

After the credentials is validaded the JWT tokens is created

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3396dztqzagiwsyty3h3.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t6w9yqsfsuqpphnfjlej.png)

The access token is generated with claims that represents the time for the token to be **_expired (exp)_**, on the example I just leave 1 minute for token to be valid, but the standard is 24 hours, the **_issuer (iss)_**, that says who issued the token, the audience (aud), that identifies the recipients that the JWT is intended for, and some user info like the **email (user_email)** and the **subject (sub)**, that represents the user's id. To deal with all JWT work I used the **jwt-golang library**, so these methods like _jwt.New_, _SignedString_ are all from the lib.

_**Notice that the secret for secure (encrypt) the JWT token I'm just using a simple word - secret, that is not a best practice. In real world you should hash your secret using some crypto algorithm and store it into a file that no one can find easily, SOO... Take the Tip**_


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6mza5t75n9atz63ixblr.png)

And to finish the refresh token is generated basically using the same idea from the access-token, taking the difference that the expiration time **(exp)** is for 30 days and only user info used is user's id, represented on the subject **(sub)**. 

After that I returned the response for the user with the access-token and refresh-token. Check bellow:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aeo1p3vyqbqo25wodied.png)


_refresh-token endpoint_

So, when the actual access-token used by the user is expired, the frontend will be notificated (receiving a 401 status code from some guarded endpoint) and will be calling the refresh-token endpoint to get another valid token. Checking the endpoint's code bellow


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jvnvj60rqt04c1qdpz8.png)

Until the line 111 I just validate the refresh token sent in the request and get the user info using the user's id sent also in the request. This user info will be used to generate another access-token. Bellow is the _ValidateToken _function on detail


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mi7vgc2kkdslwroeen9k.png)


Basically with the help of **golang-jwt library** the code parses the JWT token received on the function's argument and store all the claims from the parsed token into RefreshTokenClaims struct also received on the function's arguments. This validation is about the signature key used in the token, proving if the token was generated using the same private key of my application or not. 


And after the token key signature is validated, the audience claim and the issuer claim is checked to attempt if these are from the same issuer and audience, that the application expected to be. The issuer claim must be from the application who issued the token (in this case is my application) and the audience must be equals the audience that was designated decided by me when developed the system. With these validations the token is proved to be the same generated from my application and then I can **TRUST** in it. Generating new tokens for the user.

Notice that is generated a new access-token and a new refresh-token, that is because the new refresh-token would be used to refresh again the token, repeating all the proccess. And in the code I did not sent a error for the user in the case the audience or issuer not match the criterias, but in a real world application it would be done.

The result is new tokens generated:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/204p3g2q37vrn9p05fmb.png)



Bellow all the structs used in the code

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fymavhqflv8wkl80va9v.png)