Skip to content

Commit 057ad06

Browse files
authored
JWT auth plugin improvements (#3366)
1 parent aedae09 commit 057ad06

File tree

10 files changed

+1824
-545
lines changed

10 files changed

+1824
-545
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@graphql-yoga/plugin-jwt': patch
3+
---
4+
dependencies updates:
5+
- Added dependency [`@whatwg-node/[email protected]`
6+
↗︎](https://www.npmjs.com/package/@whatwg-node/server-plugin-cookies/v/1.0.2) (to
7+
`dependencies`)

.changeset/wise-llamas-drop.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
---
2+
'@graphql-yoga/plugin-jwt': major
3+
---
4+
5+
Re-write for the JWT plugin. This plugin can be configured now with multiple providers, lookup locations, token verification, and more.
6+
7+
The version has better version coverage, and it provides an improved API for configuring provider and custom behaviors.
8+
9+
## Breaking Change: New Plugin Configuration
10+
11+
### Signing key providers
12+
13+
❌ The `signingKey` option has be removed.
14+
❌ The `jwksUri` + `jwksOpts` options has been removed.
15+
✅ Multiple signing key providers and support for fallbacks (`singingKeyProviders[]`).
16+
✅ Improved API for defining signing key configuration.
17+
✅ Better defaults for caching and rate-limiting for remote JWKS providers.
18+
19+
#### Before
20+
21+
```ts
22+
useJWT({
23+
signingKey: "...",
24+
// or
25+
jwksUri: "http://example.com/..."
26+
jwksOpts: {
27+
// ...
28+
}
29+
})
30+
```
31+
32+
#### After
33+
34+
```ts
35+
import {
36+
createInlineSigningKeyProvider,
37+
createRemoteJwksSigningKeyProvider,
38+
useJWT
39+
} from '@graphql-yoga/plugin-jwt'
40+
41+
useJWT({
42+
// Pass one or more providers
43+
singingKeyProviders: [
44+
createRemoteJwksSigningKeyProvider({
45+
// ...
46+
})
47+
// This one also acts as a fallback in case of a fetching issue with the 1st provider
48+
createInlineSigningKeyProvider({ signingKey: "..."})
49+
]
50+
})
51+
```
52+
53+
### Improved Token Lookup
54+
55+
❌ Removed `getToken` option from the root config.
56+
✅ Added support for autmatically extracting the JWT token from cookie or header.
57+
✅ Easier setup for extracting from multiple locations.
58+
`getToken` is still available for advanced use-cases, you can pass a custom function to `lookupLocations`.
59+
60+
#### Before
61+
62+
```ts
63+
useJWT({
64+
getToken: (payload) => payload.request.headers.get("...")
65+
})
66+
```
67+
68+
#### After
69+
70+
With built-in extractors:
71+
72+
```ts
73+
imoprt { extractFromHeader, extractFromCookie, useJWT } from '@graphql-yoga/plugin-jwt'
74+
75+
const yoga = createYoga({
76+
// ...
77+
plugins: [
78+
useCookies(), // Required if "extractFromCookie" is used.
79+
useJWT({
80+
lookupLocations: [
81+
extractFromHeader({ name: 'authorization', prefix: 'Bearer' }),
82+
extractFromHeader({ name: 'x-legacy-auth' }),
83+
extractFromHeader({ name: 'x-api-key', prefix: 'API-Access' }),
84+
extractFromCookie({ name: 'browserAuth' })
85+
]
86+
})
87+
]
88+
})
89+
```
90+
91+
With a custom `getToken`:
92+
93+
```ts
94+
useJWT({
95+
lookupLocations: [
96+
(payload) => payload.request.headers.get("...")
97+
]
98+
})
99+
```
100+
101+
### Improved Verification Options
102+
103+
❌ Removed root-level config `algorithms` + `audience` + `issuer` flags.
104+
✅ Easy API for customizing token verifications (based on `jsonwebtoken` library).
105+
✅ Better defaults for token algorithm verification (before: `RS256`, after: `RS256` and `HS256`)
106+
107+
#### Before
108+
109+
```ts
110+
useJWT({
111+
algorithms: ['RS256'],
112+
audience: "my.app",
113+
issuer: "http://my-issuer"
114+
})
115+
```
116+
117+
#### After
118+
119+
```ts
120+
useJWT({
121+
tokenVerification: {
122+
algorithms: ['RS256', 'HS256'],
123+
audience: "my.app",
124+
issuer: "http://my-issuer",
125+
// You can pass more options to `jsonwebtoken.verify("...", options)` here
126+
}
127+
})
128+
```
129+
130+
### Customized Token Rejection
131+
132+
✅ New config flag `reject: { ... }` for configuring how to handle a missing or invalid tokens (enbaled by default).
133+
134+
135+
```ts
136+
useJWT({
137+
reject: {
138+
missingToken: true,
139+
invalidToken: true,
140+
}
141+
})
142+
```
143+
144+
### Flexible Context Injection
145+
146+
❌ Removed root-level config `extendContextField` flags.
147+
✅ Added root-level config `extendContext` (`boolean` / `string`)
148+
✅ Token and payload are injected now to the context (structure: `{ payload: {}, token: { value, prefix }}`)
149+
150+
#### Before
151+
152+
```ts
153+
useJWT({
154+
reject: {
155+
extendContextField: true,
156+
}
157+
})
158+
```
159+
160+
#### After
161+
162+
```ts
163+
// Can be a boolean. By default injects to "context.jwt" field
164+
useJWT({
165+
reject: {
166+
extendContext: true,
167+
}
168+
})
169+
170+
// Or an object to customize the field name
171+
useJWT({
172+
reject: {
173+
extendContext: "myJwt",
174+
}
175+
})
176+
```

packages/plugins/jwt/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"graphql-yoga": "workspace:^"
4242
},
4343
"dependencies": {
44+
"@whatwg-node/server-plugin-cookies": "1.0.2",
4445
"jsonwebtoken": "^9.0.0",
4546
"jwks-rsa": "^3.0.0",
4647
"tslib": "^2.4.0"

0 commit comments

Comments
 (0)