@atproto/oauth-provider 0.9.2 → 0.10.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/CHANGELOG.md +38 -0
- package/dist/client/client-manager.d.ts.map +1 -1
- package/dist/client/client-manager.js +0 -7
- package/dist/client/client-manager.js.map +1 -1
- package/dist/client/client.js +6 -6
- package/dist/client/client.js.map +1 -1
- package/dist/device/device-manager.js +1 -1
- package/dist/device/device-manager.js.map +1 -1
- package/dist/dpop/dpop-manager.js +15 -15
- package/dist/dpop/dpop-manager.js.map +1 -1
- package/dist/errors/access-denied-error.d.ts +4 -7
- package/dist/errors/access-denied-error.d.ts.map +1 -1
- package/dist/errors/access-denied-error.js +4 -13
- package/dist/errors/access-denied-error.js.map +1 -1
- package/dist/errors/account-selection-required-error.d.ts +2 -2
- package/dist/errors/account-selection-required-error.d.ts.map +1 -1
- package/dist/errors/account-selection-required-error.js +2 -2
- package/dist/errors/account-selection-required-error.js.map +1 -1
- package/dist/errors/authorization-error.d.ts +10 -0
- package/dist/errors/authorization-error.d.ts.map +1 -0
- package/dist/errors/authorization-error.js +31 -0
- package/dist/errors/authorization-error.js.map +1 -0
- package/dist/errors/consent-required-error.d.ts +2 -2
- package/dist/errors/consent-required-error.d.ts.map +1 -1
- package/dist/errors/consent-required-error.js +2 -2
- package/dist/errors/consent-required-error.js.map +1 -1
- package/dist/errors/error-parser.d.ts.map +1 -1
- package/dist/errors/error-parser.js +2 -1
- package/dist/errors/error-parser.js.map +1 -1
- package/dist/errors/invalid-authorization-details-error.d.ts +2 -2
- package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -1
- package/dist/errors/invalid-authorization-details-error.js +2 -2
- package/dist/errors/invalid-authorization-details-error.js.map +1 -1
- package/dist/errors/invalid-scope-error.d.ts +2 -2
- package/dist/errors/invalid-scope-error.d.ts.map +1 -1
- package/dist/errors/invalid-scope-error.js +2 -2
- package/dist/errors/invalid-scope-error.js.map +1 -1
- package/dist/errors/login-required-error.d.ts +2 -3
- package/dist/errors/login-required-error.d.ts.map +1 -1
- package/dist/errors/login-required-error.js +2 -7
- package/dist/errors/login-required-error.js.map +1 -1
- package/dist/lib/http/response.d.ts +4 -4
- package/dist/lib/http/response.d.ts.map +1 -1
- package/dist/lib/http/response.js +8 -7
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/http/stream.d.ts +1 -0
- package/dist/lib/http/stream.d.ts.map +1 -1
- package/dist/lib/http/stream.js +6 -0
- package/dist/lib/http/stream.js.map +1 -1
- package/dist/lib/util/error.d.ts +2 -0
- package/dist/lib/util/error.d.ts.map +1 -0
- package/dist/lib/util/error.js +11 -0
- package/dist/lib/util/error.js.map +1 -0
- package/dist/lib/util/zod-error.d.ts +3 -1
- package/dist/lib/util/zod-error.d.ts.map +1 -1
- package/dist/lib/util/zod-error.js +20 -10
- package/dist/lib/util/zod-error.js.map +1 -1
- package/dist/metadata/build-metadata.d.ts +0 -1
- package/dist/metadata/build-metadata.d.ts.map +1 -1
- package/dist/metadata/build-metadata.js +6 -2
- package/dist/metadata/build-metadata.js.map +1 -1
- package/dist/oauth-errors.d.ts +1 -1
- package/dist/oauth-errors.d.ts.map +1 -1
- package/dist/oauth-errors.js +1 -1
- package/dist/oauth-errors.js.map +1 -1
- package/dist/oauth-hooks.d.ts +17 -3
- package/dist/oauth-hooks.d.ts.map +1 -1
- package/dist/oauth-hooks.js +7 -4
- package/dist/oauth-hooks.js.map +1 -1
- package/dist/oauth-provider.d.ts +1 -0
- package/dist/oauth-provider.d.ts.map +1 -1
- package/dist/oauth-provider.js +35 -49
- package/dist/oauth-provider.js.map +1 -1
- package/dist/oauth-verifier.d.ts +2 -1
- package/dist/oauth-verifier.d.ts.map +1 -1
- package/dist/oauth-verifier.js.map +1 -1
- package/dist/request/request-manager.d.ts +5 -5
- package/dist/request/request-manager.d.ts.map +1 -1
- package/dist/request/request-manager.js +63 -45
- package/dist/request/request-manager.js.map +1 -1
- package/dist/request/request-store.d.ts +6 -6
- package/dist/request/request-store.d.ts.map +1 -1
- package/dist/result/authorization-result-authorize-page.d.ts +2 -3
- package/dist/result/authorization-result-authorize-page.d.ts.map +1 -1
- package/dist/router/assets/send-authorization-page.js +3 -2
- package/dist/router/assets/send-authorization-page.js.map +1 -1
- package/dist/router/create-api-middleware.d.ts.map +1 -1
- package/dist/router/create-api-middleware.js +68 -48
- package/dist/router/create-api-middleware.js.map +1 -1
- package/dist/router/create-authorization-page-middleware.d.ts.map +1 -1
- package/dist/router/create-authorization-page-middleware.js +19 -17
- package/dist/router/create-authorization-page-middleware.js.map +1 -1
- package/dist/router/create-oauth-middleware.d.ts.map +1 -1
- package/dist/router/create-oauth-middleware.js +21 -18
- package/dist/router/create-oauth-middleware.js.map +1 -1
- package/dist/router/send-redirect.js +2 -2
- package/dist/router/send-redirect.js.map +1 -1
- package/dist/token/token-manager.js +1 -1
- package/dist/token/verify-token-claims.d.ts +1 -0
- package/dist/token/verify-token-claims.d.ts.map +1 -1
- package/dist/token/verify-token-claims.js.map +1 -1
- package/dist/types/authorization-response-error.d.ts +5 -0
- package/dist/types/authorization-response-error.d.ts.map +1 -0
- package/dist/types/authorization-response-error.js +21 -0
- package/dist/types/authorization-response-error.js.map +1 -0
- package/dist/types/par-response-error.d.ts +5 -0
- package/dist/types/par-response-error.d.ts.map +1 -0
- package/dist/types/par-response-error.js +22 -0
- package/dist/types/par-response-error.js.map +1 -0
- package/package.json +7 -6
- package/src/client/client-manager.ts +0 -8
- package/src/client/client.ts +6 -6
- package/src/device/device-manager.ts +1 -1
- package/src/dpop/dpop-manager.ts +16 -16
- package/src/errors/access-denied-error.ts +6 -33
- package/src/errors/account-selection-required-error.ts +2 -2
- package/src/errors/authorization-error.ts +45 -0
- package/src/errors/consent-required-error.ts +2 -2
- package/src/errors/error-parser.ts +2 -1
- package/src/errors/invalid-authorization-details-error.ts +2 -2
- package/src/errors/invalid-scope-error.ts +2 -2
- package/src/errors/login-required-error.ts +2 -12
- package/src/lib/http/response.ts +14 -13
- package/src/lib/http/stream.ts +6 -0
- package/src/lib/util/error.ts +7 -0
- package/src/lib/util/zod-error.ts +23 -11
- package/src/metadata/build-metadata.ts +8 -3
- package/src/oauth-errors.ts +1 -1
- package/src/oauth-hooks.ts +18 -2
- package/src/oauth-provider.ts +37 -58
- package/src/oauth-verifier.ts +3 -1
- package/src/request/request-manager.ts +76 -55
- package/src/request/request-store.ts +6 -6
- package/src/result/authorization-result-authorize-page.ts +2 -3
- package/src/router/assets/send-authorization-page.ts +3 -3
- package/src/router/create-api-middleware.ts +92 -64
- package/src/router/create-authorization-page-middleware.ts +19 -21
- package/src/router/create-oauth-middleware.ts +28 -27
- package/src/router/send-redirect.ts +2 -2
- package/src/token/token-manager.ts +1 -1
- package/src/token/verify-token-claims.ts +8 -0
- package/src/types/authorization-response-error.ts +27 -0
- package/src/types/par-response-error.ts +25 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/dist/errors/invalid-parameters-error.d.ts +0 -6
- package/dist/errors/invalid-parameters-error.d.ts.map +0 -1
- package/dist/errors/invalid-parameters-error.js +0 -11
- package/dist/errors/invalid-parameters-error.js.map +0 -1
- package/dist/request/request-info.d.ts +0 -14
- package/dist/request/request-info.d.ts.map +0 -1
- package/dist/request/request-info.js +0 -3
- package/dist/request/request-info.js.map +0 -1
- package/src/errors/invalid-parameters-error.ts +0 -12
- package/src/request/request-info.ts +0 -14
@@ -1,14 +1,26 @@
|
|
1
|
-
import { ZodError } from 'zod'
|
2
|
-
|
3
|
-
export function
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
import { ZodError, ZodIssue, ZodIssueCode } from 'zod'
|
2
|
+
|
3
|
+
export function formatZodError(err: ZodError, prefix?: string): string {
|
4
|
+
const message = err.issues.length
|
5
|
+
? err.issues.map(formatZodIssue).join('; ')
|
6
|
+
: err.message // Should never happen (issues should never be empty)
|
7
|
+
return prefix ? `${prefix}: ${message}` : message
|
8
|
+
}
|
9
|
+
|
10
|
+
export function formatZodIssue(issue: ZodIssue): string {
|
11
|
+
if (issue.code === ZodIssueCode.invalid_union) {
|
12
|
+
return issue.unionErrors
|
13
|
+
.map((err) => err.issues.map(formatZodIssue).join('; '))
|
14
|
+
.join(', or ')
|
15
|
+
}
|
16
|
+
|
17
|
+
if (issue.path.length === 1 && typeof issue.path[0] === 'number') {
|
18
|
+
return `${issue.message} at index ${issue.path[0]}`
|
19
|
+
}
|
20
|
+
|
21
|
+
if (issue.path.length) {
|
22
|
+
return `${issue.message} at ${issue.path.join('.')}`
|
11
23
|
}
|
12
24
|
|
13
|
-
return
|
25
|
+
return issue.message
|
14
26
|
}
|
@@ -8,7 +8,6 @@ import { Client } from '../client/client.js'
|
|
8
8
|
import { VERIFY_ALGOS } from '../lib/util/crypto.js'
|
9
9
|
|
10
10
|
export type CustomMetadata = {
|
11
|
-
scopes_supported?: string[]
|
12
11
|
authorization_details_types_supported?: string[]
|
13
12
|
protected_resources?: string[]
|
14
13
|
}
|
@@ -27,8 +26,14 @@ export function buildMetadata(
|
|
27
26
|
|
28
27
|
scopes_supported: [
|
29
28
|
'atproto',
|
30
|
-
|
31
|
-
|
29
|
+
|
30
|
+
// These serve as hint that this server supports the transitional scopes.
|
31
|
+
// This is not a specced behavior.
|
32
|
+
'transition:email',
|
33
|
+
'transition:generic',
|
34
|
+
'transition:chat.bsky',
|
35
|
+
|
36
|
+
// Other atproto scopes can't be enumerated as they are dynamic.
|
32
37
|
],
|
33
38
|
subject_types_supported: [
|
34
39
|
//
|
package/src/oauth-errors.ts
CHANGED
@@ -3,6 +3,7 @@ export { OAuthError } from './errors/oauth-error.js'
|
|
3
3
|
|
4
4
|
export * from './errors/access-denied-error.js'
|
5
5
|
export * from './errors/account-selection-required-error.js'
|
6
|
+
export * from './errors/authorization-error.js'
|
6
7
|
export * from './errors/consent-required-error.js'
|
7
8
|
export * from './errors/handle-unavailable-error.js'
|
8
9
|
export * from './errors/invalid-authorization-details-error.js'
|
@@ -13,7 +14,6 @@ export * from './errors/invalid-dpop-key-binding-error.js'
|
|
13
14
|
export * from './errors/invalid-dpop-proof-error.js'
|
14
15
|
export * from './errors/invalid-grant-error.js'
|
15
16
|
export * from './errors/invalid-invite-code-error.js'
|
16
|
-
export * from './errors/invalid-parameters-error.js'
|
17
17
|
export * from './errors/invalid-redirect-uri-error.js'
|
18
18
|
export * from './errors/invalid-request-error.js'
|
19
19
|
export * from './errors/invalid-scope-error.js'
|
package/src/oauth-hooks.ts
CHANGED
@@ -12,7 +12,10 @@ import { ClientAuth } from './client/client-auth.js'
|
|
12
12
|
import { ClientId } from './client/client-id.js'
|
13
13
|
import { ClientInfo } from './client/client-info.js'
|
14
14
|
import { Client } from './client/client.js'
|
15
|
+
import { AccessDeniedError } from './errors/access-denied-error.js'
|
16
|
+
import { AuthorizationError } from './errors/authorization-error.js'
|
15
17
|
import { InvalidRequestError } from './errors/invalid-request-error.js'
|
18
|
+
import { OAuthError } from './errors/oauth-error.js'
|
16
19
|
import {
|
17
20
|
HcaptchaClientTokens,
|
18
21
|
HcaptchaConfig,
|
@@ -20,7 +23,6 @@ import {
|
|
20
23
|
} from './lib/hcaptcha.js'
|
21
24
|
import { RequestMetadata } from './lib/http/request.js'
|
22
25
|
import { Awaitable } from './lib/util/type.js'
|
23
|
-
import { AccessDeniedError, OAuthError } from './oauth-errors.js'
|
24
26
|
import { DeviceId, SignUpData } from './oauth-store.js'
|
25
27
|
import { RequestId } from './request/request-id.js'
|
26
28
|
|
@@ -28,6 +30,7 @@ import { RequestId } from './request/request-id.js'
|
|
28
30
|
export {
|
29
31
|
AccessDeniedError,
|
30
32
|
type Account,
|
33
|
+
AuthorizationError,
|
31
34
|
type Awaitable,
|
32
35
|
Client,
|
33
36
|
type ClientAuth,
|
@@ -115,10 +118,23 @@ export type OAuthHooks = {
|
|
115
118
|
deviceMetadata: RequestMetadata
|
116
119
|
}) => Awaitable<void>
|
117
120
|
|
121
|
+
/**
|
122
|
+
* Allows validating an authorization request (typically the requested scopes)
|
123
|
+
* before it is created. Note that the validity against the client metadata is
|
124
|
+
* already enforced by the OAuth provider.
|
125
|
+
*
|
126
|
+
* @throws {AuthorizationError}
|
127
|
+
*/
|
128
|
+
onAuthorizationRequest?: (data: {
|
129
|
+
client: Client
|
130
|
+
clientAuth: null | ClientAuth
|
131
|
+
parameters: Readonly<OAuthAuthorizationRequestParameters>
|
132
|
+
}) => Awaitable<void>
|
133
|
+
|
118
134
|
/**
|
119
135
|
* This hook is called when a client is authorized.
|
120
136
|
*
|
121
|
-
* @throws {
|
137
|
+
* @throws {AuthorizationError} to deny the authorization request and redirect
|
122
138
|
* the user to the client with an OAuth error (other errors will result in an
|
123
139
|
* internal server error being displayed to the user)
|
124
140
|
*
|
package/src/oauth-provider.ts
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import { createHash } from 'node:crypto'
|
2
2
|
import type { Redis, RedisOptions } from 'ioredis'
|
3
|
-
import { ZodError } from 'zod'
|
4
3
|
import { Jwks, Keyset } from '@atproto/jwk'
|
5
4
|
import type { Account } from '@atproto/oauth-provider-api'
|
6
5
|
import {
|
@@ -64,8 +63,8 @@ import {
|
|
64
63
|
deviceManagerOptionsSchema,
|
65
64
|
} from './device/device-manager.js'
|
66
65
|
import { DeviceStore, asDeviceStore } from './device/device-store.js'
|
67
|
-
import { AccessDeniedError } from './errors/access-denied-error.js'
|
68
66
|
import { AccountSelectionRequiredError } from './errors/account-selection-required-error.js'
|
67
|
+
import { AuthorizationError } from './errors/authorization-error.js'
|
69
68
|
import { ConsentRequiredError } from './errors/consent-required-error.js'
|
70
69
|
import { InvalidDpopKeyBindingError } from './errors/invalid-dpop-key-binding-error.js'
|
71
70
|
import { InvalidDpopProofError } from './errors/invalid-dpop-proof-error.js'
|
@@ -75,8 +74,8 @@ import { LoginRequiredError } from './errors/login-required-error.js'
|
|
75
74
|
import { HcaptchaConfig } from './lib/hcaptcha.js'
|
76
75
|
import { RequestMetadata } from './lib/http/request.js'
|
77
76
|
import { dateToRelativeSeconds } from './lib/util/date.js'
|
77
|
+
import { formatError } from './lib/util/error.js'
|
78
78
|
import { LocalizedString, MultiLangString } from './lib/util/locale.js'
|
79
|
-
import { extractZodErrorMessage } from './lib/util/zod-error.js'
|
80
79
|
import { CustomMetadata, buildMetadata } from './metadata/build-metadata.js'
|
81
80
|
import { OAuthHooks } from './oauth-hooks.js'
|
82
81
|
import {
|
@@ -104,6 +103,7 @@ import {
|
|
104
103
|
VerifyTokenClaimsOptions,
|
105
104
|
VerifyTokenClaimsResult,
|
106
105
|
} from './token/verify-token-claims.js'
|
106
|
+
import { isPARResponseError } from './types/par-response-error.js'
|
107
107
|
|
108
108
|
export { AccessTokenMode, Keyset }
|
109
109
|
export type {
|
@@ -233,6 +233,7 @@ export type OAuthProviderOptions = OAuthProviderConfig &
|
|
233
233
|
|
234
234
|
export class OAuthProvider extends OAuthVerifier {
|
235
235
|
protected readonly accessTokenMode: AccessTokenMode
|
236
|
+
protected readonly hooks: OAuthHooks
|
236
237
|
|
237
238
|
public readonly metadata: OAuthAuthorizationServerMetadata
|
238
239
|
public readonly customization: Customization
|
@@ -286,21 +287,19 @@ export class OAuthProvider extends OAuthVerifier {
|
|
286
287
|
const deviceManagerOptions: DeviceManagerOptions =
|
287
288
|
deviceManagerOptionsSchema.parse(rest)
|
288
289
|
|
289
|
-
// @NOTE: hooks don't really need a type parser, as all zod can actually
|
290
|
-
// check at runtime is the fact that the values are functions. The only way
|
291
|
-
// we would benefit from zod here would be to wrap the functions with a
|
292
|
-
// validator for the provided function's return types, which we do not add
|
293
|
-
// because it would impact runtime performance and we trust the users of
|
294
|
-
// this lib (basically ourselves) to rely on the typing system to ensure the
|
295
|
-
// correct types are returned.
|
296
|
-
const hooks: OAuthHooks = rest
|
297
|
-
|
298
290
|
// @NOTE: validation of super params (if we wanted to implement it) should
|
299
291
|
// be the responsibility of the super class.
|
300
292
|
const superOptions: OAuthVerifierOptions = rest
|
301
293
|
|
302
294
|
super({ replayStore, ...superOptions })
|
303
295
|
|
296
|
+
// @NOTE: hooks don't really need a type parser, as all zod can actually
|
297
|
+
// check at runtime is the fact that the values are functions. The only way
|
298
|
+
// we would benefit from zod here would be to wrap the functions with a
|
299
|
+
// validator for the provided function's return types, which we don't
|
300
|
+
// really need if types are respected.
|
301
|
+
this.hooks = rest
|
302
|
+
|
304
303
|
this.accessTokenMode = accessTokenMode
|
305
304
|
this.authenticationMaxAge = authenticationMaxAge
|
306
305
|
this.metadata = buildMetadata(this.issuer, this.keyset, metadata)
|
@@ -310,13 +309,13 @@ export class OAuthProvider extends OAuthVerifier {
|
|
310
309
|
this.accountManager = new AccountManager(
|
311
310
|
this.issuer,
|
312
311
|
accountStore,
|
313
|
-
hooks,
|
312
|
+
this.hooks,
|
314
313
|
this.customization,
|
315
314
|
)
|
316
315
|
this.clientManager = new ClientManager(
|
317
316
|
this.metadata,
|
318
317
|
this.keyset,
|
319
|
-
hooks,
|
318
|
+
this.hooks,
|
320
319
|
clientStore || null,
|
321
320
|
loopbackMetadata || null,
|
322
321
|
safeFetch,
|
@@ -327,12 +326,12 @@ export class OAuthProvider extends OAuthVerifier {
|
|
327
326
|
requestStore,
|
328
327
|
this.signer,
|
329
328
|
this.metadata,
|
330
|
-
hooks,
|
329
|
+
this.hooks,
|
331
330
|
)
|
332
331
|
this.tokenManager = new TokenManager(
|
333
332
|
tokenStore,
|
334
333
|
this.signer,
|
335
|
-
hooks,
|
334
|
+
this.hooks,
|
336
335
|
this.accessTokenMode,
|
337
336
|
tokenMaxAge,
|
338
337
|
)
|
@@ -448,11 +447,8 @@ export class OAuthProvider extends OAuthVerifier {
|
|
448
447
|
const parameters = await oauthAuthorizationRequestParametersSchema
|
449
448
|
.parseAsync(payload)
|
450
449
|
.catch((err) => {
|
451
|
-
const
|
452
|
-
|
453
|
-
? `Invalid request parameters: ${err.message}`
|
454
|
-
: `Invalid "request" object`
|
455
|
-
throw InvalidRequestError.from(err, message)
|
450
|
+
const msg = formatError(err, 'Invalid parameters in JAR')
|
451
|
+
throw new InvalidRequestError(msg, err)
|
456
452
|
})
|
457
453
|
|
458
454
|
return parameters
|
@@ -505,7 +501,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
505
501
|
}
|
506
502
|
}
|
507
503
|
|
508
|
-
const {
|
504
|
+
const { requestUri, expiresAt } =
|
509
505
|
await this.requestManager.createAuthorizationRequest(
|
510
506
|
client,
|
511
507
|
clientAuth,
|
@@ -514,7 +510,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
514
510
|
)
|
515
511
|
|
516
512
|
return {
|
517
|
-
request_uri:
|
513
|
+
request_uri: requestUri,
|
518
514
|
expires_in: dateToRelativeSeconds(expiresAt),
|
519
515
|
}
|
520
516
|
} catch (err) {
|
@@ -522,7 +518,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
522
518
|
// > Since initial processing of the pushed authorization request does not
|
523
519
|
// > involve resource owner interaction, error codes related to user
|
524
520
|
// > interaction, such as "access_denied", are never returned.
|
525
|
-
if (err instanceof
|
521
|
+
if (err instanceof AuthorizationError && !isPARResponseError(err.error)) {
|
526
522
|
throw new InvalidRequestError(err.error_description, err)
|
527
523
|
}
|
528
524
|
throw err
|
@@ -539,10 +535,8 @@ export class OAuthProvider extends OAuthVerifier {
|
|
539
535
|
const requestUri = await requestUriSchema
|
540
536
|
.parseAsync(query.request_uri, { path: ['query', 'request_uri'] })
|
541
537
|
.catch((err) => {
|
542
|
-
|
543
|
-
|
544
|
-
err,
|
545
|
-
)
|
538
|
+
const msg = formatError(err, 'Invalid "request_uri" query parameter')
|
539
|
+
throw new InvalidRequestError(msg, err)
|
546
540
|
})
|
547
541
|
|
548
542
|
return this.requestManager.get(requestUri, deviceId, client.id)
|
@@ -592,24 +586,24 @@ export class OAuthProvider extends OAuthVerifier {
|
|
592
586
|
const { issuer } = this
|
593
587
|
|
594
588
|
// If there is a chance to redirect the user to the client, let's do
|
595
|
-
// it by wrapping the error in an
|
596
|
-
const
|
589
|
+
// it by wrapping the error in an AuthorizationError.
|
590
|
+
const throwAuthorizationError =
|
597
591
|
'redirect_uri' in query
|
598
592
|
? (err: unknown): never => {
|
599
593
|
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.2.1
|
600
|
-
throw
|
594
|
+
throw AuthorizationError.from(query, err)
|
601
595
|
}
|
602
596
|
: null
|
603
597
|
|
604
598
|
const client = await this.clientManager
|
605
599
|
.getClient(clientCredentials.client_id)
|
606
|
-
.catch(
|
600
|
+
.catch(throwAuthorizationError)
|
607
601
|
|
608
|
-
const { parameters,
|
602
|
+
const { parameters, requestUri } = await this.processAuthorizationRequest(
|
609
603
|
client,
|
610
604
|
deviceId,
|
611
605
|
query,
|
612
|
-
).catch(
|
606
|
+
).catch(throwAuthorizationError)
|
613
607
|
|
614
608
|
try {
|
615
609
|
const sessions = await this.getSessions(client.id, deviceId, parameters)
|
@@ -632,7 +626,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
632
626
|
}
|
633
627
|
|
634
628
|
const code = await this.requestManager.setAuthorized(
|
635
|
-
|
629
|
+
requestUri,
|
636
630
|
client,
|
637
631
|
ssoSession.account,
|
638
632
|
deviceId,
|
@@ -649,7 +643,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
649
643
|
const ssoSession = ssoSessions[0]!
|
650
644
|
if (!ssoSession.loginRequired && !ssoSession.consentRequired) {
|
651
645
|
const code = await this.requestManager.setAuthorized(
|
652
|
-
|
646
|
+
requestUri,
|
653
647
|
client,
|
654
648
|
ssoSession.account,
|
655
649
|
deviceId,
|
@@ -665,7 +659,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
665
659
|
issuer,
|
666
660
|
client,
|
667
661
|
parameters,
|
668
|
-
|
662
|
+
requestUri,
|
669
663
|
sessions: sessions.map((session) => ({
|
670
664
|
// Map to avoid leaking other data that might be present in the session
|
671
665
|
account: session.account,
|
@@ -673,20 +667,10 @@ export class OAuthProvider extends OAuthVerifier {
|
|
673
667
|
loginRequired: session.loginRequired,
|
674
668
|
consentRequired: session.consentRequired,
|
675
669
|
})),
|
676
|
-
scopeDetails: parameters.scope
|
677
|
-
?.split(/\s+/)
|
678
|
-
.filter(Boolean)
|
679
|
-
.sort((a, b) => a.localeCompare(b))
|
680
|
-
.map((scope) => ({
|
681
|
-
scope,
|
682
|
-
// @TODO Allow to customize the scope descriptions (e.g.
|
683
|
-
// using a hook)
|
684
|
-
description: undefined,
|
685
|
-
})),
|
686
670
|
}
|
687
671
|
} catch (err) {
|
688
672
|
try {
|
689
|
-
await this.requestManager.delete(
|
673
|
+
await this.requestManager.delete(requestUri)
|
690
674
|
} catch {
|
691
675
|
// There are two error here. Better keep the outer one.
|
692
676
|
//
|
@@ -694,9 +678,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
694
678
|
// (allowing to log this error)
|
695
679
|
}
|
696
680
|
|
697
|
-
|
698
|
-
// likely contain the redirect_uri (using the client default).
|
699
|
-
throw AccessDeniedError.from(parameters, err, 'server_error')
|
681
|
+
throw AuthorizationError.from(parameters, err)
|
700
682
|
}
|
701
683
|
}
|
702
684
|
|
@@ -872,12 +854,8 @@ export class OAuthProvider extends OAuthVerifier {
|
|
872
854
|
const code = await codeSchema
|
873
855
|
.parseAsync(input.code, { path: ['code'] })
|
874
856
|
.catch((err) => {
|
875
|
-
|
876
|
-
|
877
|
-
err instanceof ZodError
|
878
|
-
? `Invalid code: ${err.message}`
|
879
|
-
: `Invalid code`,
|
880
|
-
)
|
857
|
+
const msg = formatError(err, 'Invalid code')
|
858
|
+
throw new InvalidGrantError(msg, err)
|
881
859
|
})
|
882
860
|
|
883
861
|
const data = await this.requestManager
|
@@ -999,7 +977,8 @@ export class OAuthProvider extends OAuthVerifier {
|
|
999
977
|
const refreshToken = await refreshTokenSchema
|
1000
978
|
.parseAsync(input.refresh_token, { path: ['refresh_token'] })
|
1001
979
|
.catch((err) => {
|
1002
|
-
|
980
|
+
const msg = formatError(err, 'Invalid refresh token')
|
981
|
+
throw new InvalidGrantError(msg, err)
|
1003
982
|
})
|
1004
983
|
|
1005
984
|
const tokenInfo = await this.tokenManager.consumeRefreshToken(refreshToken)
|
package/src/oauth-verifier.ts
CHANGED
@@ -26,6 +26,8 @@ import {
|
|
26
26
|
verifyTokenClaims,
|
27
27
|
} from './token/verify-token-claims.js'
|
28
28
|
|
29
|
+
export type * from './token/verify-token-claims.js'
|
30
|
+
|
29
31
|
export type OAuthVerifierOptions = Override<
|
30
32
|
DpopManagerOptions,
|
31
33
|
{
|
@@ -51,7 +53,7 @@ export type OAuthVerifierOptions = Override<
|
|
51
53
|
>
|
52
54
|
|
53
55
|
export { DpopNonce, Key, Keyset }
|
54
|
-
export type { DpopProof, RedisOptions, ReplayStore
|
56
|
+
export type { DpopProof, RedisOptions, ReplayStore }
|
55
57
|
|
56
58
|
export class OAuthVerifier {
|
57
59
|
public readonly issuer: OAuthIssuerIdentifier
|