1313
1414## Prerequisites
1515
16- You have to install the auth package from AdonisJS with the session guard because the jwt package use some components from the session guard.
16+ You have to install the auth package from AdonisJS
1717
1818``` bash
19- node ace add @adonisjs/auth --guard=session
19+ node ace add @adonisjs/auth
2020```
2121
2222## Setup
@@ -35,6 +35,7 @@ Go to `config/auth.ts` and add the following configuration:
3535import { defineConfig } from ' @adonisjs/auth'
3636import { InferAuthEvents , Authenticators } from ' @adonisjs/auth/types'
3737import { sessionGuard , sessionUserProvider } from ' @adonisjs/auth/session'
38+ import { tokensUserProvider } from ' @adonisjs/auth/access_tokens'
3839import { jwtGuard } from ' @maximemrf/adonisjs-jwt/jwt_config'
3940import { JwtGuardUser , BaseJwtContent } from ' @maximemrf/adonisjs-jwt/types'
4041import User from ' #models/user'
@@ -69,6 +70,11 @@ const authConfig = defineConfig({
6970 provider: sessionUserProvider ({
7071 model : () => import (' #models/user' ),
7172 }),
73+ // if you want to use refresh tokens, you have to set the refreshTokenUserProvider
74+ refreshTokenUserProvider: tokensUserProvider ({
75+ tokens: ' refreshTokens' ,
76+ model : () => import (' #models/user' ),
77+ }),
7278 // content is a function that takes the user and returns the content of the token, it can be optional, by default it returns only the user id
7379 content : <T >(user : JwtGuardUser <T >): JwtContent => {
7480 return {
@@ -81,13 +87,13 @@ const authConfig = defineConfig({
8187})
8288```
8389
84- ` tokenName ` is the name of the token passed as a cookie, it can be optional, by default it is ` token ` .
90+ ` tokenName ` is the name of the jwt token passed as a cookie, it can be optional, by default it is ` token ` .
8591
8692``` typescript
8793tokenName : ' custom-name'
8894```
8995
90- ` tokenExpiresIn ` is the time before the token expires it can be a string or a number and it can be optional.
96+ ` tokenExpiresIn ` is the time before the jwt token expires it can be a string or a number and it can be optional.
9197
9298``` typescript
9399// string
@@ -104,6 +110,67 @@ useCookies: true
104110
105111If you just want to use jwt with the bearer token no need to set ` useCookies ` to ` false ` you can just remove it.
106112
113+ ## Refresh Tokens
114+
115+ To use refresh tokens, you have to set the ` refreshTokenUserProvider ` in the guard configuration, see the example above.
116+
117+ Create a new AdonisJS migration file and run it to create the ` jwt_refresh_tokens ` table:
118+
119+ ``` typescript
120+ import { BaseSchema } from ' @adonisjs/lucid/schema'
121+
122+ export default class extends BaseSchema {
123+ protected tableName = ' jwt_refresh_tokens'
124+
125+ async up() {
126+ this .schema .createTable (this .tableName , (table ) => {
127+ table .increments ()
128+ table .integer (' tokenable_id' ).notNullable ().unsigned ()
129+ table .string (' type' ).notNullable ()
130+ table .string (' name' ).nullable ()
131+ table .string (' hash' , 80 ).notNullable ()
132+ table .text (' abilities' ).notNullable ()
133+ table .timestamp (' created_at' , { precision: 6 , useTz: true }).notNullable ()
134+ table .timestamp (' updated_at' , { precision: 6 , useTz: true }).notNullable ()
135+ table .timestamp (' expires_at' , { precision: 6 , useTz: true }).nullable ()
136+ table .timestamp (' last_used_at' , { precision: 6 , useTz: true }).nullable ()
137+ })
138+ }
139+
140+ async down() {
141+ this .schema .dropTable (this .tableName )
142+ }
143+ }
144+ ```
145+
146+ And add the ` refreshTokens ` property to your User model:
147+
148+ ``` typescript
149+ import { column , BaseModel } from ' @adonisjs/lucid/orm'
150+ import { DbAccessTokensProvider } from ' @adonisjs/auth/access_tokens'
151+
152+ export default class User extends BaseModel {
153+ @column ({ isPrimary: true })
154+ declare id: number
155+
156+ @column ()
157+ declare username: string
158+
159+ @column ()
160+ declare email: string
161+
162+ @column ()
163+ declare password: string
164+
165+ static refreshTokens = DbAccessTokensProvider .forModel (User , {
166+ prefix: ' rt_' ,
167+ table: ' jwt_refresh_tokens' ,
168+ type: ' jwt_refresh_token' ,
169+ tokenSecretLength: 40 ,
170+ })
171+ }
172+ ```
173+
107174## Authentication
108175
109176To make a protected route, you have to use the ` auth ` middleware with the ` jwt ` guard.
@@ -128,6 +195,21 @@ router.get('/', async ({ auth }) => {
128195 return auth .use (' jwt' ).getUserOrFail ()
129196})
130197.use (middleware .auth ({ guards: [' jwt' ] }))
198+
199+ // to create a refresh token to a given user
200+ import User from ' #models/user'
201+ const user = auth .getUserOrFail ()
202+ const refreshToken = await User .refreshTokens .create (user )
203+
204+ // if you use the refresh token
205+ router .post (' refresh' , async ({ auth }) => {
206+ // this will authenticate the user using the refresh token
207+ // it will delete the old refresh token and generate a new one
208+ await auth .use (' jwt' ).authenticateUsingRefreshToken ()
209+ const user = auth .getUserOrFail ()
210+ // your new refresh token
211+ user .currentToken
212+ })
131213```
132214
133215## Security
0 commit comments