@atproto/oauth-client 0.1.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.
Files changed (111) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/LICENSE.txt +7 -0
  3. package/README.md +124 -0
  4. package/dist/constants.d.ts +5 -0
  5. package/dist/constants.d.ts.map +1 -0
  6. package/dist/constants.js +8 -0
  7. package/dist/constants.js.map +1 -0
  8. package/dist/fetch-dpop.d.ts +21 -0
  9. package/dist/fetch-dpop.d.ts.map +1 -0
  10. package/dist/fetch-dpop.js +149 -0
  11. package/dist/fetch-dpop.js.map +1 -0
  12. package/dist/index.d.ts +15 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +35 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/lock.d.ts +2 -0
  17. package/dist/lock.d.ts.map +1 -0
  18. package/dist/lock.js +33 -0
  19. package/dist/lock.js.map +1 -0
  20. package/dist/oauth-agent.d.ts +29 -0
  21. package/dist/oauth-agent.d.ts.map +1 -0
  22. package/dist/oauth-agent.js +138 -0
  23. package/dist/oauth-agent.js.map +1 -0
  24. package/dist/oauth-authorization-server-metadata-resolver.d.ts +15 -0
  25. package/dist/oauth-authorization-server-metadata-resolver.d.ts.map +1 -0
  26. package/dist/oauth-authorization-server-metadata-resolver.js +56 -0
  27. package/dist/oauth-authorization-server-metadata-resolver.js.map +1 -0
  28. package/dist/oauth-callback-error.d.ts +7 -0
  29. package/dist/oauth-callback-error.d.ts.map +1 -0
  30. package/dist/oauth-callback-error.js +28 -0
  31. package/dist/oauth-callback-error.js.map +1 -0
  32. package/dist/oauth-client.d.ts +78 -0
  33. package/dist/oauth-client.d.ts.map +1 -0
  34. package/dist/oauth-client.js +278 -0
  35. package/dist/oauth-client.js.map +1 -0
  36. package/dist/oauth-protected-resource-metadata-resolver.d.ts +15 -0
  37. package/dist/oauth-protected-resource-metadata-resolver.d.ts.map +1 -0
  38. package/dist/oauth-protected-resource-metadata-resolver.js +58 -0
  39. package/dist/oauth-protected-resource-metadata-resolver.js.map +1 -0
  40. package/dist/oauth-resolver-error.d.ts +7 -0
  41. package/dist/oauth-resolver-error.d.ts.map +1 -0
  42. package/dist/oauth-resolver-error.js +17 -0
  43. package/dist/oauth-resolver-error.js.map +1 -0
  44. package/dist/oauth-resolver.d.ts +62 -0
  45. package/dist/oauth-resolver.d.ts.map +1 -0
  46. package/dist/oauth-resolver.js +73 -0
  47. package/dist/oauth-resolver.js.map +1 -0
  48. package/dist/oauth-response-error.d.ts +11 -0
  49. package/dist/oauth-response-error.d.ts.map +1 -0
  50. package/dist/oauth-response-error.js +48 -0
  51. package/dist/oauth-response-error.js.map +1 -0
  52. package/dist/oauth-server-agent.d.ts +51 -0
  53. package/dist/oauth-server-agent.d.ts.map +1 -0
  54. package/dist/oauth-server-agent.js +228 -0
  55. package/dist/oauth-server-agent.js.map +1 -0
  56. package/dist/oauth-server-factory.d.ts +20 -0
  57. package/dist/oauth-server-factory.d.ts.map +1 -0
  58. package/dist/oauth-server-factory.js +53 -0
  59. package/dist/oauth-server-factory.js.map +1 -0
  60. package/dist/refresh-error.d.ts +7 -0
  61. package/dist/refresh-error.d.ts.map +1 -0
  62. package/dist/refresh-error.js +16 -0
  63. package/dist/refresh-error.js.map +1 -0
  64. package/dist/runtime-implementation.d.ts +12 -0
  65. package/dist/runtime-implementation.d.ts.map +1 -0
  66. package/dist/runtime-implementation.js +3 -0
  67. package/dist/runtime-implementation.js.map +1 -0
  68. package/dist/runtime.d.ts +35 -0
  69. package/dist/runtime.d.ts.map +1 -0
  70. package/dist/runtime.js +185 -0
  71. package/dist/runtime.js.map +1 -0
  72. package/dist/session-getter.d.ts +30 -0
  73. package/dist/session-getter.d.ts.map +1 -0
  74. package/dist/session-getter.js +149 -0
  75. package/dist/session-getter.js.map +1 -0
  76. package/dist/types.d.ts +1580 -0
  77. package/dist/types.d.ts.map +1 -0
  78. package/dist/types.js +8 -0
  79. package/dist/types.js.map +1 -0
  80. package/dist/util.d.ts +9 -0
  81. package/dist/util.d.ts.map +1 -0
  82. package/dist/util.js +35 -0
  83. package/dist/util.js.map +1 -0
  84. package/dist/validate-client-metadata.d.ts +5 -0
  85. package/dist/validate-client-metadata.d.ts.map +1 -0
  86. package/dist/validate-client-metadata.js +46 -0
  87. package/dist/validate-client-metadata.js.map +1 -0
  88. package/package.json +46 -0
  89. package/src/constants.ts +4 -0
  90. package/src/fetch-dpop.ts +235 -0
  91. package/src/index.ts +18 -0
  92. package/src/lock.ts +34 -0
  93. package/src/oauth-agent.ts +150 -0
  94. package/src/oauth-authorization-server-metadata-resolver.ts +98 -0
  95. package/src/oauth-callback-error.ts +16 -0
  96. package/src/oauth-client.ts +440 -0
  97. package/src/oauth-protected-resource-metadata-resolver.ts +102 -0
  98. package/src/oauth-resolver-error.ts +12 -0
  99. package/src/oauth-resolver.ts +111 -0
  100. package/src/oauth-response-error.ts +31 -0
  101. package/src/oauth-server-agent.ts +275 -0
  102. package/src/oauth-server-factory.ts +41 -0
  103. package/src/refresh-error.ts +9 -0
  104. package/src/runtime-implementation.ts +17 -0
  105. package/src/runtime.ts +211 -0
  106. package/src/session-getter.ts +182 -0
  107. package/src/types.ts +26 -0
  108. package/src/util.ts +51 -0
  109. package/src/validate-client-metadata.ts +61 -0
  110. package/tsconfig.build.json +8 -0
  111. package/tsconfig.json +4 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # @atproto/oauth-client
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2482](https://github.com/bluesky-social/atproto/pull/2482) [`a8d6c1123`](https://github.com/bluesky-social/atproto/commit/a8d6c112359f5c4c0cfbe2df63443ed275f2a646) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add OAuth provider capability & support for DPoP signed tokens
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`a8d6c1123`](https://github.com/bluesky-social/atproto/commit/a8d6c112359f5c4c0cfbe2df63443ed275f2a646)]:
12
+ - @atproto-labs/simple-store-memory@0.1.0
13
+ - @atproto-labs/identity-resolver@0.1.0
14
+ - @atproto-labs/handle-resolver@0.1.0
15
+ - @atproto-labs/did-resolver@0.1.0
16
+ - @atproto-labs/simple-store@0.1.0
17
+ - @atproto/oauth-types@0.1.0
18
+ - @atproto-labs/fetch@0.1.0
19
+ - @atproto/jwk@0.1.0
20
+ - @atproto/did@0.1.0
package/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Dual MIT/Apache-2.0 License
2
+
3
+ Copyright (c) 2022-2024 Bluesky PBC, and Contributors
4
+
5
+ Except as otherwise noted in individual files, this software is licensed under the MIT license (<http://opensource.org/licenses/MIT>), or the Apache License, Version 2.0 (<http://www.apache.org/licenses/LICENSE-2.0>).
6
+
7
+ Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # @atproto/oauth-client: atproto flavoured OAuth client
2
+
3
+ Core library for implementing ATPROTO OAuth clients.
4
+
5
+ For a browser specific implementation, see `@atproto/oauth-client-browser`.
6
+ For a node specific implementation, see `@atproto/oauth-client-node`.
7
+
8
+ ```ts
9
+ import { OAuthClient } from '@atproto/oauth-client'
10
+ import { JoseKey } from '@atproto/jwk-jose' // NodeJS/Browser only
11
+
12
+ const client = new OAuthClient({
13
+ handleResolver: 'https://bsky.social', // On node, you should use a DNS based resolver
14
+ responseMode: 'query', // or "fragment" or "form_post" (for backend clients only)
15
+ clientMetadata: {
16
+ // These must be the same metadata as the one exposed on the
17
+ // "/.well-known/oauth-client-metadata" endpoint (except when using a
18
+ // loopback client)
19
+ },
20
+
21
+ runtimeImplementation: {
22
+ // A runtime specific implementation of the crypto operations needed by the
23
+ // OAuth client.
24
+
25
+ createKey(algs: string[]): Promise<Key> {
26
+ // algs is an ordered array of preferred algorithms (e.g. ['RS256', 'ES256'])
27
+
28
+ // Note, in browser environments, it is better to use non extractable keys
29
+ // to prevent leaking the private key. This can be done using the
30
+ // WebcryptoKey class from the "@atproto/jwk-webcrypto" package. The
31
+ // inconvenient of these keys (which is also what makes them stronger) is
32
+ // that the only way to persist them across browser reloads is to save
33
+ // them in the indexed DB.
34
+ return JoseKey.generate(algs)
35
+ },
36
+ getRandomValues(length: number): Uint8Array | PromiseLike<Uint8Array> {
37
+ // length is the number of bytes to generate
38
+
39
+ const bytes = new Uint8Array(byteLength)
40
+ crypto.getRandomValues(bytes)
41
+ return bytes
42
+ },
43
+ digest(
44
+ bytes: Uint8Array,
45
+ algorithm: { name: 'sha256' | 'sha384' | 'sha512' },
46
+ ): Uint8Array | PromiseLike<Uint8Array> {
47
+ // sha256 is required. Unsupported algorithms should throw an error.
48
+
49
+ const buffer = await this.crypto.subtle.digest(
50
+ algorithm.name.startsWith('sha')
51
+ ? `SHA-${algorithm.name.slice(-3)}`
52
+ : 'invalid',
53
+ bytes,
54
+ )
55
+ return new Uint8Array(buffer)
56
+ },
57
+ },
58
+
59
+ stateStore: {
60
+ // A store for saving state data while the user is being redirected to the
61
+ // authorization server.
62
+
63
+ set(key: string, internalState: InternalStateData): Promise<void> {
64
+ throw new Error('Not implemented')
65
+ },
66
+ get(key: string): Promise<InternalStateData | undefined> {
67
+ throw new Error('Not implemented')
68
+ },
69
+ del(key: string): Promise<void> {
70
+ throw new Error('Not implemented')
71
+ },
72
+ },
73
+
74
+ sessionStore: {
75
+ // A store for saving session data.
76
+
77
+ set(sub: string, session: Session): Promise<void> {
78
+ throw new Error('Not implemented')
79
+ },
80
+ get(sub: string): Promise<Session | undefined> {
81
+ throw new Error('Not implemented')
82
+ },
83
+ del(sub: string): Promise<void> {
84
+ throw new Error('Not implemented')
85
+ },
86
+ },
87
+
88
+ keyset: [
89
+ // For backend clients only, a list of private keys to use for signing
90
+ // credentials. These keys MUST correspond to the public keys exposed on the
91
+ // "jwks_uri" of the client metadata.
92
+ await JoseKey.fromImportable(process.env.PRIVATE_KEY_1),
93
+ await JoseKey.fromImportable(process.env.PRIVATE_KEY_2),
94
+ await JoseKey.fromImportable(process.env.PRIVATE_KEY_3),
95
+ ],
96
+ })
97
+ ```
98
+
99
+ ```ts
100
+ const url = await client.authorize('foo.bsky.team', {
101
+ state: '434321',
102
+ prompt: 'consent',
103
+ scope: 'email',
104
+ ui_locales: 'fr',
105
+ })
106
+
107
+ // Make user visit "url". Then, once it was redirected to the callback URI, call:
108
+
109
+ const params = new URLSearchParams('code=...&state=...')
110
+ const result = await client.callback(params)
111
+
112
+ // Verify the state (e.g. to link to an internal user)
113
+ result.state === '434321'
114
+
115
+ // The authenticated user's identifier
116
+ result.agent.sub
117
+
118
+ // Make an authenticated request to the server. New credentials will be
119
+ // automatically fetched if needed (causing sessionStore.set() to be called).
120
+ await result.agent.request('/xrpc/foo.bar')
121
+
122
+ // revoke credentials on the server (causing sessionStore.del() to be called)
123
+ await result.agent.signOut()
124
+ ```
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Per ATProto spec (OpenID uses RS256)
3
+ */
4
+ export declare const FALLBACK_ALG = "ES256";
5
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,YAAY,UAAU,CAAA"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FALLBACK_ALG = void 0;
4
+ /**
5
+ * Per ATProto spec (OpenID uses RS256)
6
+ */
7
+ exports.FALLBACK_ALG = 'ES256';
8
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,YAAY,GAAG,OAAO,CAAA"}
@@ -0,0 +1,21 @@
1
+ import { Fetch, FetchContext } from '@atproto-labs/fetch';
2
+ import { SimpleStore } from '@atproto-labs/simple-store';
3
+ import { Key } from '@atproto/jwk';
4
+ export type DpopFetchWrapperOptions<C = FetchContext> = {
5
+ key: Key;
6
+ iss: string;
7
+ nonces: SimpleStore<string, string>;
8
+ supportedAlgs?: string[];
9
+ sha256?: (input: string) => Promise<string>;
10
+ /**
11
+ * Is the intended server an authorization server (true) or a resource server
12
+ * (false)? Setting this may allow to avoid parsing the response body to
13
+ * determine the dpop-nonce.
14
+ *
15
+ * @default undefined
16
+ */
17
+ isAuthServer?: boolean;
18
+ fetch?: Fetch<C>;
19
+ };
20
+ export declare function dpopFetchWrapper<C = FetchContext>({ key, iss, supportedAlgs, nonces, sha256, isAuthServer, fetch, }: DpopFetchWrapperOptions<C>): Fetch<C>;
21
+ //# sourceMappingURL=fetch-dpop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-dpop.d.ts","sourceRoot":"","sources":["../src/fetch-dpop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAwB,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AACxD,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAUlC,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,YAAY,IAAI;IACtD,GAAG,EAAE,GAAG,CAAA;IACR,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAE3C;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;CACjB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,YAAY,EAAE,EACjD,GAAG,EACH,GAAG,EACH,aAAa,EACb,MAAM,EACN,MAAiE,EACjE,YAAY,EACZ,KAAwB,GACzB,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAwGvC"}
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dpopFetchWrapper = void 0;
4
+ const fetch_1 = require("@atproto-labs/fetch");
5
+ const base64_1 = require("multiformats/bases/base64");
6
+ // "undefined" in non https environments or environments without crypto
7
+ const subtle = globalThis.crypto?.subtle;
8
+ const ReadableStream = globalThis.ReadableStream;
9
+ function dpopFetchWrapper({ key, iss, supportedAlgs, nonces, sha256 = typeof subtle !== 'undefined' ? subtleSha256 : undefined, isAuthServer, fetch = globalThis.fetch, }) {
10
+ if (!sha256) {
11
+ throw new TypeError(`crypto.subtle is not available in this environment. Please provide a sha256 function.`);
12
+ }
13
+ const alg = negotiateAlg(key, supportedAlgs);
14
+ return async function (input, init) {
15
+ if (!key.algorithms.includes(alg)) {
16
+ throw new TypeError(`Key does not support the algorithm ${alg}`);
17
+ }
18
+ const request = init == null && input instanceof Request
19
+ ? input
20
+ : new Request(input, init);
21
+ const authorizationHeader = request.headers.get('Authorization');
22
+ const ath = authorizationHeader?.startsWith('DPoP ')
23
+ ? await sha256(authorizationHeader.slice(5))
24
+ : undefined;
25
+ const { method, url } = request;
26
+ const { origin } = new URL(url);
27
+ let initNonce;
28
+ try {
29
+ initNonce = await nonces.get(origin);
30
+ }
31
+ catch {
32
+ // Ignore get errors, we will just not send a nonce
33
+ }
34
+ const initProof = await buildProof(key, alg, iss, method, url, initNonce, ath);
35
+ request.headers.set('DPoP', initProof);
36
+ const initResponse = await fetch.call(this, request);
37
+ // Make sure the response body is consumed. Either by the caller (when the
38
+ // response is returned), of if an error is thrown (catch block).
39
+ const nextNonce = initResponse.headers.get('DPoP-Nonce');
40
+ if (!nextNonce || nextNonce === initNonce) {
41
+ // No nonce was returned or it is the same as the one we sent. No need to
42
+ // update the nonce store, or retry the request.
43
+ return initResponse;
44
+ }
45
+ // Store the fresh nonce for future requests
46
+ try {
47
+ await nonces.set(origin, nextNonce);
48
+ }
49
+ catch {
50
+ // Ignore set errors
51
+ }
52
+ const shouldRetry = await isUseDpopNonceError(initResponse, isAuthServer);
53
+ if (!shouldRetry) {
54
+ // Not a "use_dpop_nonce" error, so there is no need to retry
55
+ return initResponse;
56
+ }
57
+ // If the input stream was already consumed, we cannot retry the request. A
58
+ // solution would be to clone() the request but that would bufferize the
59
+ // entire stream in memory which can lead to memory starvation. Instead, we
60
+ // will return the original response and let the calling code handle retries.
61
+ if (input === request) {
62
+ // The input request body was consumed. We cannot retry the request.
63
+ return initResponse;
64
+ }
65
+ if (ReadableStream && init?.body instanceof ReadableStream) {
66
+ // The init body was consumed. We cannot retry the request.
67
+ return initResponse;
68
+ }
69
+ // We will now retry the request with the fresh nonce.
70
+ // The initial response body must be consumed (see cancelBody's doc).
71
+ await (0, fetch_1.cancelBody)(initResponse, 'log');
72
+ const nextProof = await buildProof(key, alg, iss, method, url, nextNonce, ath);
73
+ const nextRequest = new Request(input, init);
74
+ nextRequest.headers.set('DPoP', nextProof);
75
+ return fetch.call(this, nextRequest);
76
+ };
77
+ }
78
+ exports.dpopFetchWrapper = dpopFetchWrapper;
79
+ async function buildProof(key, alg, iss, htm, htu, nonce, ath) {
80
+ if (!key.bareJwk) {
81
+ throw new Error('Only asymmetric keys can be used as DPoP proofs');
82
+ }
83
+ const now = Math.floor(Date.now() / 1e3);
84
+ return key.createJwt({
85
+ alg,
86
+ typ: 'dpop+jwt',
87
+ jwk: key.bareJwk,
88
+ }, {
89
+ iss,
90
+ iat: now,
91
+ exp: now + 10,
92
+ // Any collision will cause the request to be rejected by the server. no biggie.
93
+ jti: Math.random().toString(36).slice(2),
94
+ htm,
95
+ htu,
96
+ nonce,
97
+ ath,
98
+ });
99
+ }
100
+ async function isUseDpopNonceError(response, isAuthServer) {
101
+ // https://datatracker.ietf.org/doc/html/rfc6750#section-3
102
+ // https://datatracker.ietf.org/doc/html/rfc9449#name-resource-server-provided-no
103
+ if (isAuthServer === undefined || isAuthServer === false) {
104
+ if (response.status === 401) {
105
+ const wwwAuth = response.headers.get('WWW-Authenticate');
106
+ if (wwwAuth?.startsWith('DPoP')) {
107
+ return wwwAuth.includes('error="use_dpop_nonce"');
108
+ }
109
+ }
110
+ }
111
+ // https://datatracker.ietf.org/doc/html/rfc9449#name-authorization-server-provid
112
+ if (isAuthServer === undefined || isAuthServer === true) {
113
+ if (response.status === 400) {
114
+ try {
115
+ const json = await (0, fetch_1.peekJson)(response, 10 * 1024);
116
+ return typeof json === 'object' && json?.['error'] === 'use_dpop_nonce';
117
+ }
118
+ catch {
119
+ // Response too big (to be "use_dpop_nonce" error) or invalid JSON
120
+ return false;
121
+ }
122
+ }
123
+ }
124
+ return false;
125
+ }
126
+ function negotiateAlg(key, supportedAlgs) {
127
+ if (supportedAlgs) {
128
+ // Use order of supportedAlgs as preference
129
+ const alg = supportedAlgs.find((a) => key.algorithms.includes(a));
130
+ if (alg)
131
+ return alg;
132
+ }
133
+ else {
134
+ const [alg] = key.algorithms;
135
+ if (alg)
136
+ return alg;
137
+ }
138
+ throw new Error('Key does not match any alg supported by the server');
139
+ }
140
+ async function subtleSha256(input) {
141
+ if (subtle == null) {
142
+ throw new Error(`crypto.subtle is not available in this environment. Please provide a sha256 function.`);
143
+ }
144
+ const bytes = new TextEncoder().encode(input);
145
+ const digest = await subtle.digest('SHA-256', bytes);
146
+ const digestBytes = new Uint8Array(digest);
147
+ return base64_1.base64url.baseEncode(digestBytes);
148
+ }
149
+ //# sourceMappingURL=fetch-dpop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-dpop.js","sourceRoot":"","sources":["../src/fetch-dpop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export { FetchError, FetchRequestError, FetchResponseError, } from '@atproto-labs/fetch';
2
+ export * from './oauth-agent.js';
3
+ export * from './oauth-authorization-server-metadata-resolver.js';
4
+ export * from './oauth-callback-error.js';
5
+ export * from './oauth-client.js';
6
+ export * from './oauth-protected-resource-metadata-resolver.js';
7
+ export * from './oauth-resolver-error.js';
8
+ export * from './oauth-response-error.js';
9
+ export * from './oauth-server-agent.js';
10
+ export * from './oauth-server-factory.js';
11
+ export * from './refresh-error.js';
12
+ export * from './runtime-implementation.js';
13
+ export * from './session-getter.js';
14
+ export * from './types.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,mDAAmD,CAAA;AACjE,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iDAAiD,CAAA;AAC/D,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2BAA2B,CAAA;AACzC,cAAc,oBAAoB,CAAA;AAClC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,qBAAqB,CAAA;AACnC,cAAc,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.FetchResponseError = exports.FetchRequestError = exports.FetchError = void 0;
18
+ var fetch_1 = require("@atproto-labs/fetch");
19
+ Object.defineProperty(exports, "FetchError", { enumerable: true, get: function () { return fetch_1.FetchError; } });
20
+ Object.defineProperty(exports, "FetchRequestError", { enumerable: true, get: function () { return fetch_1.FetchRequestError; } });
21
+ Object.defineProperty(exports, "FetchResponseError", { enumerable: true, get: function () { return fetch_1.FetchResponseError; } });
22
+ __exportStar(require("./oauth-agent.js"), exports);
23
+ __exportStar(require("./oauth-authorization-server-metadata-resolver.js"), exports);
24
+ __exportStar(require("./oauth-callback-error.js"), exports);
25
+ __exportStar(require("./oauth-client.js"), exports);
26
+ __exportStar(require("./oauth-protected-resource-metadata-resolver.js"), exports);
27
+ __exportStar(require("./oauth-resolver-error.js"), exports);
28
+ __exportStar(require("./oauth-response-error.js"), exports);
29
+ __exportStar(require("./oauth-server-agent.js"), exports);
30
+ __exportStar(require("./oauth-server-factory.js"), exports);
31
+ __exportStar(require("./refresh-error.js"), exports);
32
+ __exportStar(require("./runtime-implementation.js"), exports);
33
+ __exportStar(require("./session-getter.js"), exports);
34
+ __exportStar(require("./types.js"), exports);
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,6CAI4B;AAH1B,mGAAA,UAAU,OAAA;AACV,0GAAA,iBAAiB,OAAA;AACjB,2GAAA,kBAAkB,OAAA;AAEpB,mDAAgC;AAChC,oFAAiE;AACjE,4DAAyC;AACzC,oDAAiC;AACjC,kFAA+D;AAC/D,4DAAyC;AACzC,4DAAyC;AACzC,0DAAuC;AACvC,4DAAyC;AACzC,qDAAkC;AAClC,8DAA2C;AAC3C,sDAAmC;AACnC,6CAA0B"}
package/dist/lock.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function requestLocalLock<T>(name: string, fn: () => T | PromiseLike<T>): Promise<T>;
2
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"AAsBA,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAC3B,OAAO,CAAC,CAAC,CAAC,CAQZ"}
package/dist/lock.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requestLocalLock = void 0;
4
+ const locks = new Map();
5
+ function acquireLocalLock(name) {
6
+ return new Promise((resolveAcquire) => {
7
+ const prev = locks.get(name) ?? Promise.resolve();
8
+ const next = prev.then(() => {
9
+ return new Promise((resolveRelease) => {
10
+ const release = () => {
11
+ // Only delete the lock if it is still the current one
12
+ if (locks.get(name) === next)
13
+ locks.delete(name);
14
+ resolveRelease();
15
+ };
16
+ resolveAcquire(release);
17
+ });
18
+ });
19
+ locks.set(name, next);
20
+ });
21
+ }
22
+ function requestLocalLock(name, fn) {
23
+ return acquireLocalLock(name).then(async (release) => {
24
+ try {
25
+ return await fn();
26
+ }
27
+ finally {
28
+ release();
29
+ }
30
+ });
31
+ }
32
+ exports.requestLocalLock = requestLocalLock;
33
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":";;;AAAA,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAA;AAE/C,SAAS,gBAAgB,CAAC,IAAa;IACrC,OAAO,IAAI,OAAO,CAAC,CAAC,cAAc,EAAE,EAAE;QACpC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAA;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;YAC1B,OAAO,IAAI,OAAO,CAAO,CAAC,cAAc,EAAE,EAAE;gBAC1C,MAAM,OAAO,GAAG,GAAG,EAAE;oBACnB,sDAAsD;oBACtD,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI;wBAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;oBAEhD,cAAc,EAAE,CAAA;gBAClB,CAAC,CAAA;gBAED,cAAc,CAAC,OAAO,CAAC,CAAA;YACzB,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,gBAAgB,CAC9B,IAAY,EACZ,EAA4B;IAE5B,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACnD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAA;QACnB,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAXD,4CAWC"}
@@ -0,0 +1,29 @@
1
+ import { Fetch } from '@atproto-labs/fetch';
2
+ import { JwtPayload } from '@atproto/jwk';
3
+ import { OAuthAuthorizationServerMetadata } from '@atproto/oauth-types';
4
+ import { OAuthServerAgent, TokenSet } from './oauth-server-agent.js';
5
+ import { SessionGetter } from './session-getter.js';
6
+ export declare class OAuthAgent {
7
+ readonly server: OAuthServerAgent;
8
+ readonly sub: string;
9
+ private readonly sessionGetter;
10
+ protected dpopFetch: Fetch<unknown>;
11
+ constructor(server: OAuthServerAgent, sub: string, sessionGetter: SessionGetter, fetch?: Fetch);
12
+ get serverMetadata(): Readonly<OAuthAuthorizationServerMetadata>;
13
+ refreshIfNeeded(): Promise<void>;
14
+ /**
15
+ * @param refresh See {@link SessionGetter.getSession}
16
+ */
17
+ protected getTokenSet(refresh?: boolean): Promise<TokenSet>;
18
+ getInfo(): Promise<{
19
+ userinfo?: JwtPayload;
20
+ expired?: boolean;
21
+ scope?: string;
22
+ iss: string;
23
+ aud: string;
24
+ sub: string;
25
+ }>;
26
+ signOut(): Promise<void>;
27
+ request(pathname: string, init?: RequestInit): Promise<Response>;
28
+ }
29
+ //# sourceMappingURL=oauth-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-agent.d.ts","sourceRoot":"","sources":["../src/oauth-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAa,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAmB,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAA;AAGvE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAMnD,qBAAa,UAAU;aAIH,MAAM,EAAE,gBAAgB;aACxB,GAAG,EAAE,MAAM;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IALhC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;gBAGjB,MAAM,EAAE,gBAAgB,EACxB,GAAG,EAAE,MAAM,EACV,aAAa,EAAE,aAAa,EAC7C,KAAK,GAAE,KAAwB;IAajC,IAAI,cAAc,IAAI,QAAQ,CAAC,gCAAgC,CAAC,CAE/D;IAEY,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7C;;OAEG;cACa,WAAW,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAK3D,OAAO,IAAI,OAAO,CAAC;QACvB,QAAQ,CAAC,EAAE,UAAU,CAAA;QACrB,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,GAAG,EAAE,MAAM,CAAA;QACX,GAAG,EAAE,MAAM,CAAA;QACX,GAAG,EAAE,MAAM,CAAA;KACZ,CAAC;IAkBI,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IASxB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;CAqDvE"}
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OAuthAgent = void 0;
4
+ const fetch_1 = require("@atproto-labs/fetch");
5
+ const jwk_1 = require("@atproto/jwk");
6
+ const fetch_dpop_js_1 = require("./fetch-dpop.js");
7
+ const ReadableStream = globalThis.ReadableStream;
8
+ class OAuthAgent {
9
+ constructor(server, sub, sessionGetter, fetch = globalThis.fetch) {
10
+ Object.defineProperty(this, "server", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: server
15
+ });
16
+ Object.defineProperty(this, "sub", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: sub
21
+ });
22
+ Object.defineProperty(this, "sessionGetter", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: sessionGetter
27
+ });
28
+ Object.defineProperty(this, "dpopFetch", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: void 0
33
+ });
34
+ this.dpopFetch = (0, fetch_dpop_js_1.dpopFetchWrapper)({
35
+ fetch: (0, fetch_1.bindFetch)(fetch),
36
+ iss: server.clientMetadata.client_id,
37
+ key: server.dpopKey,
38
+ supportedAlgs: server.serverMetadata.dpop_signing_alg_values_supported,
39
+ sha256: async (v) => server.runtime.sha256(v),
40
+ nonces: server.dpopNonces,
41
+ isAuthServer: false,
42
+ });
43
+ }
44
+ get serverMetadata() {
45
+ return this.server.serverMetadata;
46
+ }
47
+ async refreshIfNeeded() {
48
+ await this.getTokenSet(undefined);
49
+ }
50
+ /**
51
+ * @param refresh See {@link SessionGetter.getSession}
52
+ */
53
+ async getTokenSet(refresh) {
54
+ const { tokenSet } = await this.sessionGetter.getSession(this.sub, refresh);
55
+ return tokenSet;
56
+ }
57
+ async getInfo() {
58
+ const tokenSet = await this.getTokenSet();
59
+ return {
60
+ userinfo: tokenSet.id_token
61
+ ? (0, jwk_1.unsafeDecodeJwt)(tokenSet.id_token).payload
62
+ : undefined,
63
+ expired: tokenSet.expires_at == null
64
+ ? undefined
65
+ : new Date(tokenSet.expires_at).getTime() < Date.now() - 5e3,
66
+ scope: tokenSet.scope,
67
+ iss: tokenSet.iss,
68
+ aud: tokenSet.aud,
69
+ sub: tokenSet.sub,
70
+ };
71
+ }
72
+ async signOut() {
73
+ try {
74
+ const { tokenSet } = await this.sessionGetter.getSession(this.sub, false);
75
+ await this.server.revoke(tokenSet.access_token);
76
+ }
77
+ finally {
78
+ await this.sessionGetter.delStored(this.sub);
79
+ }
80
+ }
81
+ async request(pathname, init) {
82
+ // This will try and refresh the token if it is known to be expired
83
+ const tokenSet = await this.getTokenSet(undefined);
84
+ const initialUrl = new URL(pathname, tokenSet.aud);
85
+ const initialAuth = `${tokenSet.token_type} ${tokenSet.access_token}`;
86
+ const headers = new Headers(init?.headers);
87
+ headers.set('Authorization', initialAuth);
88
+ const initialResponse = await this.dpopFetch(initialUrl, {
89
+ ...init,
90
+ headers,
91
+ });
92
+ // If the token is not expired, we don't need to refresh it
93
+ if (!isTokenExpiredResponse(initialResponse)) {
94
+ return initialResponse;
95
+ }
96
+ let tokenSetFresh;
97
+ try {
98
+ // "true" here will cause the token to be refreshed
99
+ tokenSetFresh = await this.getTokenSet(true);
100
+ }
101
+ catch (err) {
102
+ return initialResponse;
103
+ }
104
+ // The stream was already consumed. We cannot retry the request. A solution
105
+ // would be to tee() the input stream but that would bufferize the entire
106
+ // stream in memory which can lead to memory starvation. Instead, we will
107
+ // return the original response and let the calling code handle retries.
108
+ if (ReadableStream && init?.body instanceof ReadableStream) {
109
+ return initialResponse;
110
+ }
111
+ const finalAuth = `${tokenSetFresh.token_type} ${tokenSetFresh.access_token}`;
112
+ const finalUrl = new URL(pathname, tokenSetFresh.aud);
113
+ headers.set('Authorization', finalAuth);
114
+ const finalResponse = await this.dpopFetch(finalUrl, { ...init, headers });
115
+ // There is no need to keep the session in the store if the token is expired
116
+ // and there is no way to refresh it.
117
+ if (isTokenExpiredResponse(finalResponse)) {
118
+ // TODO: Is there a "softer" way to handle this, e.g. by marking the
119
+ // session as "expired" and allow the user to trigger a new login?
120
+ await this.sessionGetter.delStored(this.sub);
121
+ }
122
+ return finalResponse;
123
+ }
124
+ }
125
+ exports.OAuthAgent = OAuthAgent;
126
+ /**
127
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc6750#section-3}
128
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc9449#name-resource-server-provided-no}
129
+ */
130
+ function isTokenExpiredResponse(response) {
131
+ if (response.status !== 401)
132
+ return false;
133
+ const wwwAuth = response.headers.get('WWW-Authenticate');
134
+ return (wwwAuth != null &&
135
+ (wwwAuth.startsWith('Bearer ') || wwwAuth.startsWith('DPoP ')) &&
136
+ wwwAuth.includes('error="invalid_token"'));
137
+ }
138
+ //# sourceMappingURL=oauth-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-agent.js","sourceRoot":"","sources":["../src/oauth-agent.ts"],"names":[],"mappings":"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"}