I'm currently developing a website using Go with the Gin framework for the backend and Next.js for the frontend. While I have most of the authentication logic implemented, I'm uncertain about how to handle access tokens and refresh tokens.
My plan is to store the refresh token in the database and the access token in cookies. However, I'm confused about when to refresh the access token. Should it be done when the user receives a 401 error, indicating that their token has expired? If so, how should I handle the refresh process?
My concern is that if I refresh the access token using the expired access-token, so when expired access-token get exposed then whoever got the expire token can get a new token, potentially allowing someone to obtain a new access token. How can I securely handle the refresh process to avoid this risk? Or should I use a timer which refreshes the access token when it is about to get expired? I appreciate any guidance on how to properly handle access token refreshment in this scenario.
I firstly tried to store both token in cookies then I thought it make no sense and then I stored refresh-token in database but so confused don't know how to refresh access-token based on refresh token which is saved in the database
I have addressed the issue myself. If there are any concerns with this approach, please let me know.
Upon login, I create two JWT tokens: a refresh token and an access token. Each token contains a unique key. These tokens are stored in cookies, and a session is created in the database. The session document structure is as follows:
type Session struct {
ID primitive.ObjectID `bson:"_id"`
AccessTokenID string `bson:"accessTokenID" validate:"required"`
RefreshTokenID string `bson:"refreshTokenID" validate:"required"`
UsedRefreshTokens map[string]bool `bson:"usedRefreshTokens" validate:"required"`
}
The AccessTokenID and RefreshTokenID are saved in the session document. Additionally, a UsedRefreshTokens object is created to store the IDs of used refresh tokens.
During a token refresh process, I check if the AccessTokenID and RefreshTokenID in the request match those stored in the database. Furthermore, I verify if the RefreshTokenID is present in the UsedRefreshTokens object. If the RefreshTokenID is found in the UsedRefreshTokens, it indicates potential token misuse (e.g., token reuse), leading to the deletion of the session from the database and removal of cookies.
On logout, I delete the session from the database and clear the cookies.