@envelop/generic-auth 4.3.0 → 4.3.1-alpha-72027859.0
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 +73 -73
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -25,11 +25,11 @@ Then, define your authentication methods:
|
|
|
25
25
|
Use this method to only extract the user from the context, with any custom code, for example:
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
|
-
import { ResolveUserFn } from '@envelop/generic-auth'
|
|
28
|
+
import { ResolveUserFn } from '@envelop/generic-auth'
|
|
29
29
|
|
|
30
30
|
type UserType = {
|
|
31
|
-
id: string
|
|
32
|
-
}
|
|
31
|
+
id: string
|
|
32
|
+
}
|
|
33
33
|
|
|
34
34
|
const resolveUserFn: ResolveUserFn<UserType> = async context => {
|
|
35
35
|
// Here you can implement any custom sync/async code, and use the context built so far in Envelop and the HTTP request
|
|
@@ -38,15 +38,15 @@ const resolveUserFn: ResolveUserFn<UserType> = async context => {
|
|
|
38
38
|
// Make sure to either return `null` or the user object.
|
|
39
39
|
|
|
40
40
|
try {
|
|
41
|
-
const user = await context.authApi.authenticateUser(context.req.headers.authorization)
|
|
41
|
+
const user = await context.authApi.authenticateUser(context.req.headers.authorization)
|
|
42
42
|
|
|
43
|
-
return user
|
|
43
|
+
return user
|
|
44
44
|
} catch (e) {
|
|
45
|
-
console.error('Failed to validate token')
|
|
45
|
+
console.error('Failed to validate token')
|
|
46
46
|
|
|
47
|
-
return null
|
|
47
|
+
return null
|
|
48
48
|
}
|
|
49
|
-
}
|
|
49
|
+
}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
2. Define an optional validation method by implementing `validateUser`:
|
|
@@ -54,18 +54,18 @@ const resolveUserFn: ResolveUserFn<UserType> = async context => {
|
|
|
54
54
|
This method is optional; the default method will just verify the value returned by `resolveUser` and throw an error in case of a false value (`false | null | undefined`).
|
|
55
55
|
|
|
56
56
|
```ts
|
|
57
|
-
import { ValidateUserFn } from '@envelop/generic-auth'
|
|
57
|
+
import { ValidateUserFn } from '@envelop/generic-auth'
|
|
58
58
|
|
|
59
|
-
const validateUser: ValidateUserFn<UserType> =
|
|
59
|
+
const validateUser: ValidateUserFn<UserType> = params => {
|
|
60
60
|
// Here you can implement any custom to check if the user is valid and have access to the server.
|
|
61
61
|
// This method is being triggered in different flows, based on the mode you chose to implement.
|
|
62
62
|
|
|
63
63
|
// If you are using the `protect-auth-directive` mode, you'll also get 2 additional parameters: the resolver parameters as object and the DirectiveNode of the auth directive.
|
|
64
64
|
|
|
65
65
|
if (!user) {
|
|
66
|
-
throw new Error(`Unauthenticated!`)
|
|
66
|
+
throw new Error(`Unauthenticated!`)
|
|
67
67
|
}
|
|
68
|
-
}
|
|
68
|
+
}
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
Now, configure your plugin based on the mode you wish to use:
|
|
@@ -77,18 +77,18 @@ This mode offers complete protection for the entire API. It protects your entire
|
|
|
77
77
|
To setup this mode, use the following config:
|
|
78
78
|
|
|
79
79
|
```ts
|
|
80
|
-
import { envelop } from '@envelop/core'
|
|
81
|
-
import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth'
|
|
80
|
+
import { envelop } from '@envelop/core'
|
|
81
|
+
import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth'
|
|
82
82
|
|
|
83
83
|
type UserType = {
|
|
84
|
-
id: string
|
|
85
|
-
}
|
|
84
|
+
id: string
|
|
85
|
+
}
|
|
86
86
|
const resolveUserFn: ResolveUserFn<UserType> = async context => {
|
|
87
87
|
/* ... */
|
|
88
|
-
}
|
|
89
|
-
const validateUser: ValidateUserFn<UserType> =
|
|
88
|
+
}
|
|
89
|
+
const validateUser: ValidateUserFn<UserType> = params => {
|
|
90
90
|
/* ... */
|
|
91
|
-
}
|
|
91
|
+
}
|
|
92
92
|
|
|
93
93
|
const getEnveloped = envelop({
|
|
94
94
|
plugins: [
|
|
@@ -96,10 +96,10 @@ const getEnveloped = envelop({
|
|
|
96
96
|
useGenericAuth({
|
|
97
97
|
resolveUserFn,
|
|
98
98
|
validateUser,
|
|
99
|
-
mode: 'protect-all'
|
|
100
|
-
})
|
|
101
|
-
]
|
|
102
|
-
})
|
|
99
|
+
mode: 'protect-all'
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
})
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
##### Allow unauthenticated access for specific fields using a field `directive`
|
|
@@ -123,7 +123,7 @@ type Query {
|
|
|
123
123
|
##### Allow unauthenticated access for specific fields using a field extension
|
|
124
124
|
|
|
125
125
|
```typescript
|
|
126
|
-
import { GraphQLObjectType, GraphQLInt } from 'graphql'
|
|
126
|
+
import { GraphQLObjectType, GraphQLInt } from 'graphql'
|
|
127
127
|
|
|
128
128
|
const GraphQLQueryType = new GraphQLObjectType({
|
|
129
129
|
name: 'Query',
|
|
@@ -132,11 +132,11 @@ const GraphQLQueryType = new GraphQLObjectType({
|
|
|
132
132
|
type: GraphQLInt,
|
|
133
133
|
resolve: () => 1,
|
|
134
134
|
extensions: {
|
|
135
|
-
skipAuth: true
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
})
|
|
135
|
+
skipAuth: true
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
> If you want to use a different directive for authentication, you can use the `directiveOrExtensionFieldName` configuration to customize it.
|
|
@@ -146,18 +146,18 @@ const GraphQLQueryType = new GraphQLObjectType({
|
|
|
146
146
|
This mode uses the plugin to inject the authenticated user into the `context`, and later you can verify it in your resolvers.
|
|
147
147
|
|
|
148
148
|
```ts
|
|
149
|
-
import { envelop } from '@envelop/core'
|
|
150
|
-
import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth'
|
|
149
|
+
import { envelop } from '@envelop/core'
|
|
150
|
+
import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth'
|
|
151
151
|
|
|
152
152
|
type UserType = {
|
|
153
|
-
id: string
|
|
154
|
-
}
|
|
153
|
+
id: string
|
|
154
|
+
}
|
|
155
155
|
const resolveUserFn: ResolveUserFn<UserType> = async context => {
|
|
156
156
|
/* ... */
|
|
157
|
-
}
|
|
158
|
-
const validateUser: ValidateUserFn<UserType> = async
|
|
157
|
+
}
|
|
158
|
+
const validateUser: ValidateUserFn<UserType> = async params => {
|
|
159
159
|
/* ... */
|
|
160
|
-
}
|
|
160
|
+
}
|
|
161
161
|
|
|
162
162
|
const getEnveloped = envelop({
|
|
163
163
|
plugins: [
|
|
@@ -165,10 +165,10 @@ const getEnveloped = envelop({
|
|
|
165
165
|
useGenericAuth({
|
|
166
166
|
resolveUserFn,
|
|
167
167
|
validateUser,
|
|
168
|
-
mode: 'resolve-only'
|
|
169
|
-
})
|
|
170
|
-
]
|
|
171
|
-
})
|
|
168
|
+
mode: 'resolve-only'
|
|
169
|
+
})
|
|
170
|
+
]
|
|
171
|
+
})
|
|
172
172
|
```
|
|
173
173
|
|
|
174
174
|
Then, in your resolvers, you can execute the check method based on your needs:
|
|
@@ -177,13 +177,13 @@ Then, in your resolvers, you can execute the check method based on your needs:
|
|
|
177
177
|
const resolvers = {
|
|
178
178
|
Query: {
|
|
179
179
|
me: async (root, args, context) => {
|
|
180
|
-
await context.validateUser()
|
|
181
|
-
const currentUser = context.currentUser
|
|
180
|
+
await context.validateUser()
|
|
181
|
+
const currentUser = context.currentUser
|
|
182
182
|
|
|
183
|
-
return currentUser
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
183
|
+
return currentUser
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
187
|
```
|
|
188
188
|
|
|
189
189
|
#### Option #3 - `protect-granular`
|
|
@@ -191,18 +191,18 @@ const resolvers = {
|
|
|
191
191
|
This mode is similar to option #2, but it uses the `@auth` SDL directive or `auth` field extension for protecting specific GraphQL fields.
|
|
192
192
|
|
|
193
193
|
```ts
|
|
194
|
-
import { envelop } from '@envelop/core'
|
|
195
|
-
import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth'
|
|
194
|
+
import { envelop } from '@envelop/core'
|
|
195
|
+
import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth'
|
|
196
196
|
|
|
197
197
|
type UserType = {
|
|
198
|
-
id: string
|
|
199
|
-
}
|
|
198
|
+
id: string
|
|
199
|
+
}
|
|
200
200
|
const resolveUserFn: ResolveUserFn<UserType> = async context => {
|
|
201
201
|
/* ... */
|
|
202
|
-
}
|
|
203
|
-
const validateUser: ValidateUserFn<UserType> =
|
|
202
|
+
}
|
|
203
|
+
const validateUser: ValidateUserFn<UserType> = params => {
|
|
204
204
|
/* ... */
|
|
205
|
-
}
|
|
205
|
+
}
|
|
206
206
|
|
|
207
207
|
const getEnveloped = envelop({
|
|
208
208
|
plugins: [
|
|
@@ -210,10 +210,10 @@ const getEnveloped = envelop({
|
|
|
210
210
|
useGenericAuth({
|
|
211
211
|
resolveUserFn,
|
|
212
212
|
validateUser,
|
|
213
|
-
mode: 'protect-granular'
|
|
214
|
-
})
|
|
215
|
-
]
|
|
216
|
-
})
|
|
213
|
+
mode: 'protect-granular'
|
|
214
|
+
})
|
|
215
|
+
]
|
|
216
|
+
})
|
|
217
217
|
```
|
|
218
218
|
|
|
219
219
|
##### Protect a field using a field `directive`
|
|
@@ -237,7 +237,7 @@ type Query {
|
|
|
237
237
|
##### Protect a field using a field extension
|
|
238
238
|
|
|
239
239
|
```typescript
|
|
240
|
-
import { GraphQLObjectType, GraphQLInt } from 'graphql'
|
|
240
|
+
import { GraphQLObjectType, GraphQLInt } from 'graphql'
|
|
241
241
|
|
|
242
242
|
const GraphQLQueryType = new GraphQLObjectType({
|
|
243
243
|
name: 'Query',
|
|
@@ -246,11 +246,11 @@ const GraphQLQueryType = new GraphQLObjectType({
|
|
|
246
246
|
type: GraphQLInt,
|
|
247
247
|
resolve: () => 1,
|
|
248
248
|
extensions: {
|
|
249
|
-
auth: true
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
})
|
|
249
|
+
auth: true
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
254
|
```
|
|
255
255
|
|
|
256
256
|
> If you are using a different field extension for authentication, you can pass `directiveOrExtensionFieldName` configuration to customize it.
|
|
@@ -260,17 +260,17 @@ const GraphQLQueryType = new GraphQLObjectType({
|
|
|
260
260
|
You can also specify a custom `validateUser` function and get access to a handy object while using the `protect-all` and `protect-granular` mode:
|
|
261
261
|
|
|
262
262
|
```ts
|
|
263
|
-
import { GraphQLError } from 'graphql'
|
|
264
|
-
import { ValidateUserFn } from '@envelop/generic-auth'
|
|
263
|
+
import { GraphQLError } from 'graphql'
|
|
264
|
+
import { ValidateUserFn } from '@envelop/generic-auth'
|
|
265
265
|
|
|
266
266
|
const validateUser: ValidateUserFn<UserType> = async ({ user }) => {
|
|
267
267
|
// Now you can use the 3rd parameter to implement custom logic for user validation, with access
|
|
268
268
|
// to the resolver data and information.
|
|
269
269
|
|
|
270
270
|
if (!user) {
|
|
271
|
-
return new GraphQLError(`Unauthenticated.`)
|
|
271
|
+
return new GraphQLError(`Unauthenticated.`)
|
|
272
272
|
}
|
|
273
|
-
}
|
|
273
|
+
}
|
|
274
274
|
```
|
|
275
275
|
|
|
276
276
|
And it's also possible to add custom parameters to your `@auth` directive. Here's an example for adding role-aware authentication:
|
|
@@ -287,21 +287,21 @@ directive @auth(role: Role!) on FIELD_DEFINITION
|
|
|
287
287
|
Then, you use the `directiveNode` parameter to check the arguments:
|
|
288
288
|
|
|
289
289
|
```ts
|
|
290
|
-
import { ValidateUserFn } from '@envelop/generic-auth'
|
|
290
|
+
import { ValidateUserFn } from '@envelop/generic-auth'
|
|
291
291
|
|
|
292
292
|
const validateUser: ValidateUserFn<UserType> = async ({ user, fieldAuthDirectiveNode }) => {
|
|
293
293
|
// Now you can use the 3rd parameter to implement custom logic for user validation, with access
|
|
294
294
|
// to the resolver data and information.
|
|
295
295
|
|
|
296
296
|
if (!user) {
|
|
297
|
-
throw new Error(`Unauthenticated!`)
|
|
297
|
+
throw new Error(`Unauthenticated!`)
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
const valueNode = fieldAuthDirectiveNode.arguments.find(arg => arg.name.value === 'role').value as EnumValueNode
|
|
301
|
-
const role = valueNode.value
|
|
300
|
+
const valueNode = fieldAuthDirectiveNode.arguments.find(arg => arg.name.value === 'role').value as EnumValueNode
|
|
301
|
+
const role = valueNode.value
|
|
302
302
|
|
|
303
303
|
if (role !== user.role) {
|
|
304
|
-
throw new Error(`No permissions!`)
|
|
304
|
+
throw new Error(`No permissions!`)
|
|
305
305
|
}
|
|
306
|
-
}
|
|
306
|
+
}
|
|
307
307
|
```
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@envelop/generic-auth",
|
|
3
|
-
"version": "4.3.0",
|
|
3
|
+
"version": "4.3.1-alpha-72027859.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@envelop/core": "
|
|
6
|
+
"@envelop/core": "2.4.1-alpha-72027859.0",
|
|
7
7
|
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@envelop/extended-validation": "
|
|
10
|
+
"@envelop/extended-validation": "1.7.1-alpha-72027859.0"
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|