@maximemrf/adonisjs-jwt 0.7.0 → 0.7.1

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
@@ -79,6 +79,11 @@ const authConfig = defineConfig({
79
79
  refreshTokenExpiresIn: '7d',
80
80
  // ability to separate cookie usage for refresh token
81
81
  useCookiesForRefreshToken: true,
82
+ // ability to configure the cookies options
83
+ cookie: {
84
+ httpOnly: true,
85
+ secure: true,
86
+ },
82
87
  // limit the abilities of the refresh token
83
88
  refreshTokenAbilities: ['refresh_token'],
84
89
  // 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
@@ -116,6 +121,19 @@ useCookies: true
116
121
 
117
122
  If you just want to use jwt with the bearer token no need to set `useCookies` to `false` you can just remove it.
118
123
 
124
+ You can also pass options to the cookies. Note that `maxAge` and `expires` are omitted from the options because they are automatically handled by the package based on the token validity (`tokenExpiresIn` and `refreshTokenExpiresIn`).
125
+ By default, `httpOnly: true` and `secure: true` are enforced for better security, but you can override them using the `cookie` object configuration.
126
+
127
+ ```typescript
128
+ cookie: {
129
+ httpOnly: true, // Default
130
+ secure: true, // Default
131
+ path: '/',
132
+ sameSite: 'lax',
133
+ // maxAge and expires cannot be set here
134
+ }
135
+ ```
136
+
119
137
  ## JWKS
120
138
 
121
139
  You can use JWKS to verify the token by setting the `jwks` option in the guard configuration.
@@ -1,6 +1,6 @@
1
1
  import { GuardConfigProvider } from '@adonisjs/auth/types';
2
2
  import type { HttpContext } from '@adonisjs/core/http';
3
- import { JwtGuardUser, JwtUserProviderContract } from './types.js';
3
+ import { JwtGuardUser, JwtUserProviderContract, JwtCookieOptions } 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';
@@ -17,4 +17,5 @@ export declare function jwtGuard<UserProvider extends JwtUserProviderContract<un
17
17
  secret?: string;
18
18
  content: <T>(user: JwtGuardUser<T>) => Record<string | number, any>;
19
19
  jwks?: Options;
20
+ cookie?: JwtCookieOptions;
20
21
  }): GuardConfigProvider<(ctx: HttpContext) => JwtGuard<UserProvider>>;
@@ -14,6 +14,7 @@ export function jwtGuard(config) {
14
14
  refreshTokenAbilities: config.refreshTokenAbilities,
15
15
  content: config.content,
16
16
  jwks: config.jwks,
17
+ cookie: config.cookie,
17
18
  };
18
19
  return (ctx) => new JwtGuard(ctx, config.provider, options);
19
20
  },
package/build/src/jwt.js CHANGED
@@ -10,6 +10,7 @@ export class JwtGuard {
10
10
  #tokenName;
11
11
  #refreshTokenName = 'refreshToken';
12
12
  #jwksManager;
13
+ #cookieOptions;
13
14
  constructor(ctx, userProvider, option) {
14
15
  this.#ctx = ctx;
15
16
  this.#userProvider = userProvider;
@@ -19,6 +20,11 @@ export class JwtGuard {
19
20
  this.#options.content = (user) => ({ userId: user.getId() });
20
21
  this.#tokenName = this.#options.tokenName ?? 'token';
21
22
  this.#jwksManager = this.#options.jwks ? new JwksManager(this.#options.jwks) : undefined;
23
+ this.#cookieOptions = {
24
+ httpOnly: true,
25
+ secure: true,
26
+ ...this.#options.cookie,
27
+ };
22
28
  }
23
29
  /**
24
30
  * A unique name for the guard driver
@@ -64,12 +70,14 @@ export class JwtGuard {
64
70
  }
65
71
  if (this.#options.useCookies) {
66
72
  this.#ctx.response.cookie(`${this.#tokenName}`, token, {
67
- httpOnly: true,
73
+ ...this.#cookieOptions,
74
+ maxAge: this.#options.expiresIn,
68
75
  });
69
76
  }
70
77
  if (this.#options.useCookiesForRefreshToken && refreshToken) {
71
78
  this.#ctx.response.cookie(`${this.#refreshTokenName}`, refreshToken, {
72
- httpOnly: true,
79
+ ...this.#cookieOptions,
80
+ maxAge: this.#options.refreshTokenExpiresIn,
73
81
  });
74
82
  }
75
83
  return {
@@ -94,17 +102,10 @@ export class JwtGuard {
94
102
  return this.getUserOrFail();
95
103
  }
96
104
  this.authenticationAttempted = true;
97
- const cookieHeader = this.#ctx.request.request.headers.cookie;
98
- let token;
99
105
  /**
100
- * If cookies are enabled, then read the token from the cookies
106
+ * Try to read the token from the cookies.
101
107
  */
102
- if (cookieHeader) {
103
- const regex = new RegExp(`${this.#tokenName}=([^;]*)`);
104
- token =
105
- this.#ctx.request.cookie(`${this.#tokenName}`) ??
106
- (this.#ctx.request.request.headers.cookie.match(regex) || [])[1];
107
- }
108
+ let token = this.#ctx.request.cookie(`${this.#tokenName}`);
108
109
  /**
109
110
  * If token is missing on cookies, then try to read it from the header authorization
110
111
  */
@@ -2,6 +2,8 @@ import { symbols } from '@adonisjs/auth';
2
2
  import type { StringValue } from 'ms';
3
3
  import { AccessTokensUserProviderContract } from '@adonisjs/auth/types/access_tokens';
4
4
  import { Options } from 'jwks-rsa';
5
+ import type { CookieOptions } from '@adonisjs/core/types/http';
6
+ export type JwtCookieOptions = Omit<Partial<CookieOptions>, 'maxAge' | 'expires'>;
5
7
  /**
6
8
  * The bridge between the User provider and the
7
9
  * Guard
@@ -49,5 +51,6 @@ export type JwtGuardOptions<RealUser extends any = unknown> = {
49
51
  useCookies?: boolean;
50
52
  useCookiesForRefreshToken?: boolean;
51
53
  refreshTokenAbilities?: string[];
54
+ cookie?: JwtCookieOptions;
52
55
  content?: (user: JwtGuardUser<RealUser>) => Record<string, any>;
53
56
  };
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",
4
+ "version": "0.7.1",
5
5
  "engines": {
6
6
  "node": ">=20.6.0"
7
7
  },
@@ -35,8 +35,8 @@
35
35
  },
36
36
  "devDependencies": {
37
37
  "@adonisjs/assembler": "^7.8.2",
38
- "@adonisjs/auth": "^9.5.1",
39
- "@adonisjs/core": "^6.19.3",
38
+ "@adonisjs/auth": "^9.6.0",
39
+ "@adonisjs/core": "^6.20.0",
40
40
  "@adonisjs/eslint-config": "^2.1.2",
41
41
  "@adonisjs/lucid": "^21.8.2",
42
42
  "@adonisjs/prettier-config": "^1.4.5",
@@ -44,16 +44,16 @@
44
44
  "@japa/assert": "^4.2.0",
45
45
  "@japa/file-system": "^3.0.0",
46
46
  "@japa/runner": "^5.3.0",
47
- "@types/nock": "^10.0.3",
48
- "@swc/core": "^1.15.10",
47
+ "@types/nock": "^11.1.0",
48
+ "@swc/core": "^1.15.11",
49
49
  "@types/node": "^22.15.18",
50
50
  "c8": "^10.1.3",
51
51
  "copyfiles": "^2.4.1",
52
52
  "del-cli": "^7.0.0",
53
53
  "eslint": "^9.39.2",
54
54
  "luxon": "^3.7.2",
55
- "nock": "^14.0.10",
56
- "np": "^11.0.1",
55
+ "nock": "^14.0.11",
56
+ "np": "^11.0.2",
57
57
  "prettier": "^3.8.1",
58
58
  "sqlite3": "^5.1.7",
59
59
  "timekeeper": "^2.3.1",