Skip to content

Commit a6fe8d5

Browse files
committed
docs(refresh token)
1 parent 24d1d13 commit a6fe8d5

File tree

1 file changed

+86
-4
lines changed

1 file changed

+86
-4
lines changed

README.md

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
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:
3535
import { defineConfig } from '@adonisjs/auth'
3636
import { InferAuthEvents, Authenticators } from '@adonisjs/auth/types'
3737
import { sessionGuard, sessionUserProvider } from '@adonisjs/auth/session'
38+
import { tokensUserProvider } from '@adonisjs/auth/access_tokens'
3839
import { jwtGuard } from '@maximemrf/adonisjs-jwt/jwt_config'
3940
import { JwtGuardUser, BaseJwtContent } from '@maximemrf/adonisjs-jwt/types'
4041
import 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
8793
tokenName: '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

105111
If 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

109176
To 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

Comments
 (0)