@maximemrf/adonisjs-jwt 0.7.0-alpha.0 → 0.7.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -131,7 +131,13 @@ export default class extends BaseSchema {
131
131
  async up() {
132
132
  this.schema.createTable(this.tableName, (table) => {
133
133
  table.increments()
134
- table.integer('tokenable_id').notNullable().unsigned()
134
+ table
135
+ .integer('tokenable_id')
136
+ .notNullable()
137
+ .unsigned()
138
+ .references('id')
139
+ .inTable('users')
140
+ .onDelete('CASCADE')
135
141
  table.string('type').notNullable()
136
142
  table.string('name').nullable()
137
143
  table.string('hash', 80).notNullable()
@@ -193,16 +199,18 @@ router.post('login', async ({ request, auth }) => {
193
199
  })
194
200
 
195
201
  // if the jwt guard is the default guard
196
- router.get('/', async ({ auth }) => {
197
- return auth.getUserOrFail()
198
- })
199
- .use(middleware.auth())
202
+ router
203
+ .get('/', async ({ auth }) => {
204
+ return auth.getUserOrFail()
205
+ })
206
+ .use(middleware.auth())
200
207
 
201
208
  // if the jwt guard is not the default guard
202
- router.get('/', async ({ auth }) => {
203
- return auth.use('jwt').getUserOrFail()
204
- })
205
- .use(middleware.auth({ guards: ['jwt'] }))
209
+ router
210
+ .get('/', async ({ auth }) => {
211
+ return auth.use('jwt').getUserOrFail()
212
+ })
213
+ .use(middleware.auth({ guards: ['jwt'] }))
206
214
 
207
215
  // if you use the refresh token
208
216
  router.post('jwt/refresh', async ({ auth }) => {
@@ -4,6 +4,7 @@ import { JwtGuardUser, JwtUserProviderContract } from './types.js';
4
4
  import { JwtGuard } from './jwt.js';
5
5
  import type { StringValue } from 'ms';
6
6
  import { AccessTokensUserProviderContract } from '@adonisjs/auth/types/access_tokens';
7
+ import { Options } from 'jwks-rsa';
7
8
  export declare function jwtGuard<UserProvider extends JwtUserProviderContract<unknown>>(config: {
8
9
  provider: UserProvider;
9
10
  refreshTokenUserProvider?: AccessTokensUserProviderContract<unknown>;
@@ -15,4 +16,5 @@ export declare function jwtGuard<UserProvider extends JwtUserProviderContract<un
15
16
  refreshTokenAbilities?: string[];
16
17
  secret?: string;
17
18
  content: <T>(user: JwtGuardUser<T>) => Record<string | number, any>;
19
+ jwks?: Options;
18
20
  }): GuardConfigProvider<(ctx: HttpContext) => JwtGuard<UserProvider>>;
@@ -1,4 +1,5 @@
1
1
  import { JwtGuard } from './jwt.js';
2
+ import { JwksManager } from './jwks.js';
2
3
  export function jwtGuard(config) {
3
4
  return {
4
5
  async resolver(_, app) {
@@ -13,6 +14,8 @@ export function jwtGuard(config) {
13
14
  useCookiesForRefreshToken: config.useCookiesForRefreshToken,
14
15
  refreshTokenAbilities: config.refreshTokenAbilities,
15
16
  content: config.content,
17
+ jwks: config.jwks,
18
+ jwksClient: config.jwks ? new JwksManager(config.jwks).getClient() : undefined,
16
19
  };
17
20
  return (ctx) => new JwtGuard(ctx, config.provider, options);
18
21
  },
@@ -0,0 +1,7 @@
1
+ import { Options, JwksClient } from 'jwks-rsa';
2
+ export declare class JwksManager {
3
+ private client;
4
+ constructor(options: Options);
5
+ getClient(): JwksClient;
6
+ getSigningKey(kid: string): Promise<string>;
7
+ }
@@ -0,0 +1,14 @@
1
+ import { JwksClient } from 'jwks-rsa';
2
+ export class JwksManager {
3
+ client;
4
+ constructor(options) {
5
+ this.client = new JwksClient(options);
6
+ }
7
+ getClient() {
8
+ return this.client;
9
+ }
10
+ async getSigningKey(kid) {
11
+ const key = await this.client.getSigningKey(kid);
12
+ return key.getPublicKey();
13
+ }
14
+ }
package/build/src/jwt.js CHANGED
@@ -8,6 +8,7 @@ export class JwtGuard {
8
8
  #options;
9
9
  #tokenName;
10
10
  #refreshTokenName = 'refreshToken';
11
+ #jwksManager;
11
12
  constructor(ctx, userProvider, option) {
12
13
  this.#ctx = ctx;
13
14
  this.#userProvider = userProvider;
@@ -16,6 +17,7 @@ export class JwtGuard {
16
17
  if (!this.#options.content)
17
18
  this.#options.content = (user) => ({ userId: user.getId() });
18
19
  this.#tokenName = this.#options.tokenName ?? 'token';
20
+ this.#jwksManager = this.#options.jwksManager;
19
21
  }
20
22
  /**
21
23
  * A unique name for the guard driver
@@ -126,14 +128,26 @@ export class JwtGuard {
126
128
  */
127
129
  let payload;
128
130
  try {
129
- payload = jwt.verify(token, this.#options.secret);
131
+ if (this.#jwksManager) {
132
+ const decoded = jwt.decode(token, { complete: true });
133
+ if (!decoded || !decoded.header || !decoded.header.kid) {
134
+ throw new errors.E_UNAUTHORIZED_ACCESS('Unauthorized access', {
135
+ guardDriverName: this.driverName,
136
+ });
137
+ }
138
+ const key = await this.#jwksManager.getSigningKey(decoded.header.kid);
139
+ payload = jwt.verify(token, key);
140
+ }
141
+ else {
142
+ payload = jwt.verify(token, this.#options.secret);
143
+ }
130
144
  }
131
145
  catch (error) {
132
146
  throw new errors.E_UNAUTHORIZED_ACCESS('Unauthorized access', {
133
147
  guardDriverName: this.driverName,
134
148
  });
135
149
  }
136
- if (typeof payload !== 'object' || !('userId' in payload)) {
150
+ if (!payload || typeof payload !== 'object' || !('userId' in payload)) {
137
151
  throw new errors.E_UNAUTHORIZED_ACCESS('Unauthorized access', {
138
152
  guardDriverName: this.driverName,
139
153
  });
@@ -1,6 +1,8 @@
1
1
  import { symbols } from '@adonisjs/auth';
2
2
  import type { StringValue } from 'ms';
3
3
  import { AccessTokensUserProviderContract } from '@adonisjs/auth/types/access_tokens';
4
+ import { Options } from 'jwks-rsa';
5
+ import { JwksManager } from './jwks.js';
4
6
  /**
5
7
  * The bridge between the User provider and the
6
8
  * Guard
@@ -40,6 +42,8 @@ export type BaseJwtContent = {
40
42
  };
41
43
  export type JwtGuardOptions<RealUser extends any = unknown> = {
42
44
  secret: string;
45
+ jwks?: Options;
46
+ jwksManager?: JwksManager;
43
47
  refreshTokenUserProvider?: AccessTokensUserProviderContract<RealUser>;
44
48
  tokenName?: string;
45
49
  expiresIn?: number | StringValue;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maximemrf/adonisjs-jwt",
3
3
  "description": "Adonisjs v6 package for authentication with jwt token",
4
- "version": "0.7.0-alpha.0",
4
+ "version": "0.7.0-alpha.2",
5
5
  "engines": {
6
6
  "node": ">=20.6.0"
7
7
  },
@@ -35,24 +35,24 @@
35
35
  },
36
36
  "devDependencies": {
37
37
  "@adonisjs/assembler": "^7.8.2",
38
- "@adonisjs/auth": "^9.5.0",
39
- "@adonisjs/core": "^6.19.0",
38
+ "@adonisjs/auth": "^9.5.1",
39
+ "@adonisjs/core": "^6.19.3",
40
40
  "@adonisjs/eslint-config": "^2.1.2",
41
- "@adonisjs/lucid": "^21.8.0",
41
+ "@adonisjs/lucid": "^21.8.2",
42
42
  "@adonisjs/prettier-config": "^1.4.5",
43
43
  "@adonisjs/tsconfig": "^1.4.1",
44
- "@japa/assert": "^4.1.1",
45
- "@japa/file-system": "^2.3.2",
46
- "@japa/runner": "^4.4.0",
47
- "@swc/core": "^1.13.5",
44
+ "@japa/assert": "^4.2.0",
45
+ "@japa/file-system": "^3.0.0",
46
+ "@japa/runner": "^5.3.0",
47
+ "@swc/core": "^1.15.8",
48
48
  "@types/node": "^22.15.18",
49
49
  "c8": "^10.1.3",
50
50
  "copyfiles": "^2.4.1",
51
51
  "del-cli": "^7.0.0",
52
- "eslint": "^9.37.0",
52
+ "eslint": "^9.39.2",
53
53
  "luxon": "^3.7.2",
54
- "np": "^10.2.0",
55
- "prettier": "^3.6.2",
54
+ "np": "^10.3.0",
55
+ "prettier": "^3.8.0",
56
56
  "sqlite3": "^5.1.7",
57
57
  "timekeeper": "^2.3.1",
58
58
  "ts-node-maintained": "^10.9.6",
@@ -60,7 +60,8 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "@types/jsonwebtoken": "^9.0.10",
63
- "jsonwebtoken": "^9.0.2",
63
+ "jsonwebtoken": "^9.0.3",
64
+ "jwks-rsa": "^3.2.2",
64
65
  "ms": "^2.1.3"
65
66
  },
66
67
  "peerDependencies": {
@@ -97,4 +98,4 @@
97
98
  "tests/**"
98
99
  ]
99
100
  }
100
- }
101
+ }