@atproto/oauth-client 0.1.0 → 0.1.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/CHANGELOG.md +15 -0
- package/README.md +162 -32
- package/dist/errors/token-invalid-error.d.ts +7 -0
- package/dist/errors/token-invalid-error.d.ts.map +1 -0
- package/dist/errors/token-invalid-error.js +16 -0
- package/dist/errors/token-invalid-error.js.map +1 -0
- package/dist/errors/token-refresh-error.d.ts +7 -0
- package/dist/errors/token-refresh-error.d.ts.map +1 -0
- package/dist/errors/token-refresh-error.js +16 -0
- package/dist/errors/token-refresh-error.js.map +1 -0
- package/dist/errors/token-revoked-error.d.ts +7 -0
- package/dist/errors/token-revoked-error.d.ts.map +1 -0
- package/dist/errors/token-revoked-error.js +16 -0
- package/dist/errors/token-revoked-error.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/lock.d.ts +2 -1
- package/dist/lock.d.ts.map +1 -1
- package/dist/lock.js +2 -2
- package/dist/lock.js.map +1 -1
- package/dist/oauth-agent.d.ts.map +1 -1
- package/dist/oauth-agent.js +14 -9
- package/dist/oauth-agent.js.map +1 -1
- package/dist/oauth-client.d.ts +250 -20
- package/dist/oauth-client.d.ts.map +1 -1
- package/dist/oauth-client.js +67 -9
- package/dist/oauth-client.js.map +1 -1
- package/dist/oauth-resolver.d.ts +5 -4
- package/dist/oauth-resolver.d.ts.map +1 -1
- package/dist/oauth-resolver.js.map +1 -1
- package/dist/oauth-server-agent.d.ts.map +1 -1
- package/dist/oauth-server-agent.js +85 -29
- package/dist/oauth-server-agent.js.map +1 -1
- package/dist/runtime-implementation.d.ts +10 -5
- package/dist/runtime-implementation.d.ts.map +1 -1
- package/dist/runtime.d.ts +3 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +18 -12
- package/dist/runtime.js.map +1 -1
- package/dist/session-getter.d.ts +19 -0
- package/dist/session-getter.d.ts.map +1 -1
- package/dist/session-getter.js +134 -42
- package/dist/session-getter.js.map +1 -1
- package/dist/state-store.d.ts +11 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/state-store.js +3 -0
- package/dist/state-store.js.map +1 -0
- package/dist/types.d.ts +3 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +10 -3
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +43 -23
- package/dist/util.js.map +1 -1
- package/dist/validate-client-metadata.d.ts.map +1 -1
- package/dist/validate-client-metadata.js +17 -0
- package/dist/validate-client-metadata.js.map +1 -1
- package/package.json +8 -8
- package/src/errors/token-invalid-error.ts +9 -0
- package/src/errors/token-refresh-error.ts +9 -0
- package/src/errors/token-revoked-error.ts +9 -0
- package/src/index.ts +11 -1
- package/src/lock.ts +3 -4
- package/src/oauth-agent.ts +20 -9
- package/src/oauth-client.ts +113 -31
- package/src/oauth-resolver.ts +4 -4
- package/src/oauth-server-agent.ts +9 -9
- package/src/runtime-implementation.ts +19 -11
- package/src/runtime.ts +13 -17
- package/src/session-getter.ts +135 -71
- package/src/state-store.ts +12 -0
- package/src/types.ts +5 -2
- package/src/util.ts +63 -32
- package/src/validate-client-metadata.ts +18 -0
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# @atproto/oauth-client
|
2
2
|
|
3
|
+
## 0.1.1
|
4
|
+
|
5
|
+
### Patch Changes
|
6
|
+
|
7
|
+
- [#2633](https://github.com/bluesky-social/atproto/pull/2633) [`acc9093d2`](https://github.com/bluesky-social/atproto/commit/acc9093d2845eba02b68fb2f9db33e4f1b59bb10) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add event emitting capability to OAuthClient
|
8
|
+
|
9
|
+
- Updated dependencies [[`acc9093d2`](https://github.com/bluesky-social/atproto/commit/acc9093d2845eba02b68fb2f9db33e4f1b59bb10), [`acc9093d2`](https://github.com/bluesky-social/atproto/commit/acc9093d2845eba02b68fb2f9db33e4f1b59bb10), [`acc9093d2`](https://github.com/bluesky-social/atproto/commit/acc9093d2845eba02b68fb2f9db33e4f1b59bb10), [`acc9093d2`](https://github.com/bluesky-social/atproto/commit/acc9093d2845eba02b68fb2f9db33e4f1b59bb10)]:
|
10
|
+
- @atproto/oauth-types@0.1.1
|
11
|
+
- @atproto/jwk@0.1.1
|
12
|
+
- @atproto-labs/identity-resolver@0.1.1
|
13
|
+
- @atproto-labs/handle-resolver@0.1.1
|
14
|
+
- @atproto-labs/did-resolver@0.1.1
|
15
|
+
- @atproto-labs/simple-store@0.1.1
|
16
|
+
- @atproto-labs/simple-store-memory@0.1.1
|
17
|
+
|
3
18
|
## 0.1.0
|
4
19
|
|
5
20
|
### Minor Changes
|
package/README.md
CHANGED
@@ -1,59 +1,86 @@
|
|
1
1
|
# @atproto/oauth-client: atproto flavoured OAuth client
|
2
2
|
|
3
|
-
Core library for implementing ATPROTO OAuth clients.
|
3
|
+
Core library for implementing [ATPROTO] OAuth clients.
|
4
4
|
|
5
|
-
For a browser specific implementation, see
|
6
|
-
For a node specific implementation, see
|
5
|
+
For a browser specific implementation, see [@atproto/oauth-client-browser](https://www.npmjs.com/package/@atproto/oauth-client-browser).
|
6
|
+
For a node specific implementation, see
|
7
|
+
[@atproto/oauth-client-node](https://www.npmjs.com/package/@atproto/oauth-client-node).
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
### Configuration
|
7
12
|
|
8
13
|
```ts
|
9
14
|
import { OAuthClient } from '@atproto/oauth-client'
|
10
15
|
import { JoseKey } from '@atproto/jwk-jose' // NodeJS/Browser only
|
11
16
|
|
12
17
|
const client = new OAuthClient({
|
13
|
-
handleResolver: 'https://
|
14
|
-
responseMode: 'query', // or "fragment" or "form_post" (
|
18
|
+
handleResolver: 'https://my-backend.example', // backend instances should use a DNS based resolver
|
19
|
+
responseMode: 'query', // or "fragment" (frontend only) or "form_post" (backend only)
|
20
|
+
|
21
|
+
// These must be the same metadata as the one exposed on the
|
22
|
+
// "client_id" endpoint (except when using a loopback client)
|
15
23
|
clientMetadata: {
|
16
|
-
|
17
|
-
|
18
|
-
// loopback client)
|
24
|
+
client_id: 'https://my-app.example/atproto-oauth-client.json',
|
25
|
+
jwks_uri: 'https://my-app.example/jwks.json',
|
19
26
|
},
|
20
27
|
|
21
28
|
runtimeImplementation: {
|
22
29
|
// A runtime specific implementation of the crypto operations needed by the
|
23
|
-
// OAuth client.
|
30
|
+
// OAuth client. See "@atproto/oauth-client-browser" for a browser specific
|
31
|
+
// implementation. The following example is suitable for use in NodeJS.
|
24
32
|
|
25
33
|
createKey(algs: string[]): Promise<Key> {
|
26
34
|
// algs is an ordered array of preferred algorithms (e.g. ['RS256', 'ES256'])
|
27
35
|
|
28
36
|
// Note, in browser environments, it is better to use non extractable keys
|
29
|
-
// to prevent
|
30
|
-
// WebcryptoKey class from the "@atproto/jwk-webcrypto" package. The
|
37
|
+
// to prevent the private key from being stolen. This can be done using
|
38
|
+
// the WebcryptoKey class from the "@atproto/jwk-webcrypto" package. The
|
31
39
|
// inconvenient of these keys (which is also what makes them stronger) is
|
32
40
|
// that the only way to persist them across browser reloads is to save
|
33
41
|
// them in the indexed DB.
|
34
42
|
return JoseKey.generate(algs)
|
35
43
|
},
|
36
|
-
getRandomValues(length: number): Uint8Array | PromiseLike<Uint8Array> {
|
37
|
-
// length is the number of bytes to generate
|
38
44
|
|
39
|
-
|
40
|
-
crypto.getRandomValues(
|
41
|
-
return bytes
|
45
|
+
getRandomValues(length: number): Uint8Array | PromiseLike<Uint8Array> {
|
46
|
+
return crypto.getRandomValues(new Uint8Array(length))
|
42
47
|
},
|
48
|
+
|
43
49
|
digest(
|
44
50
|
bytes: Uint8Array,
|
45
|
-
algorithm: { name:
|
51
|
+
algorithm: { name: string },
|
46
52
|
): Uint8Array | PromiseLike<Uint8Array> {
|
47
53
|
// sha256 is required. Unsupported algorithms should throw an error.
|
48
54
|
|
49
|
-
|
50
|
-
algorithm.name.
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
55
|
+
if (algorithm.name.startsWith('sha')) {
|
56
|
+
const subtleAlgo = `SHA-${algorithm.name.slice(3)}`
|
57
|
+
const buffer = await crypto.subtle.digest(subtleAlgo, bytes)
|
58
|
+
return new Uint8Array(buffer)
|
59
|
+
}
|
60
|
+
|
61
|
+
throw new TypeError(`Unsupported algorithm: ${algorithm.name}`)
|
56
62
|
},
|
63
|
+
|
64
|
+
requestLock: <T>(name: string, fn: () => T | PromiseLike<T>): Promise T => {
|
65
|
+
// This function is used to prevent concurrent refreshes of the same
|
66
|
+
// credentials. It is important to ensure that only one refresh is done at
|
67
|
+
// a time to prevent the sessions from being revoked.
|
68
|
+
|
69
|
+
// The following example shows a simple in-memory lock. In a real
|
70
|
+
// application, you should use a more robust solution (e.g. a system wide
|
71
|
+
// lock manager). Note that not providing a lock will result in an
|
72
|
+
// in-memory lock to be used (DO NOT copy-paste the following code).
|
73
|
+
|
74
|
+
declare const locks: Map<string, Promise<void>>
|
75
|
+
|
76
|
+
const current = locks.get(name) || Promise.resolve()
|
77
|
+
const next = current.then(fn).catch(() => {}).finally(() => {
|
78
|
+
if (locks.get(name) === next) locks.delete(name)
|
79
|
+
})
|
80
|
+
|
81
|
+
locks.set(name, next)
|
82
|
+
return next
|
83
|
+
}
|
57
84
|
},
|
58
85
|
|
59
86
|
stateStore: {
|
@@ -88,7 +115,8 @@ const client = new OAuthClient({
|
|
88
115
|
keyset: [
|
89
116
|
// For backend clients only, a list of private keys to use for signing
|
90
117
|
// credentials. These keys MUST correspond to the public keys exposed on the
|
91
|
-
// "jwks_uri" of the client metadata.
|
118
|
+
// "jwks_uri" of the client metadata. Note that the jwks JSON corresponding
|
119
|
+
// to the following keys can be obtained using the `client.jwks` getter.
|
92
120
|
await JoseKey.fromImportable(process.env.PRIVATE_KEY_1),
|
93
121
|
await JoseKey.fromImportable(process.env.PRIVATE_KEY_2),
|
94
122
|
await JoseKey.fromImportable(process.env.PRIVATE_KEY_3),
|
@@ -96,6 +124,8 @@ const client = new OAuthClient({
|
|
96
124
|
})
|
97
125
|
```
|
98
126
|
|
127
|
+
### Authentication
|
128
|
+
|
99
129
|
```ts
|
100
130
|
const url = await client.authorize('foo.bsky.team', {
|
101
131
|
state: '434321',
|
@@ -103,22 +133,122 @@ const url = await client.authorize('foo.bsky.team', {
|
|
103
133
|
scope: 'email',
|
104
134
|
ui_locales: 'fr',
|
105
135
|
})
|
136
|
+
```
|
106
137
|
|
107
|
-
|
138
|
+
Make user visit `url`. Then, once it was redirected to the callback URI, perform the following:
|
108
139
|
|
140
|
+
```ts
|
141
|
+
// Parse the query params from the callback URI
|
109
142
|
const params = new URLSearchParams('code=...&state=...')
|
110
|
-
const result = await client.callback(params)
|
111
143
|
|
112
|
-
//
|
113
|
-
|
144
|
+
// Process the callback using the OAuth client
|
145
|
+
const { agent, state } = await client.callback(params)
|
114
146
|
|
115
|
-
//
|
116
|
-
|
147
|
+
// Verify the state (e.g. to link to an internal user)
|
148
|
+
state === '434321' // true
|
117
149
|
|
118
150
|
// Make an authenticated request to the server. New credentials will be
|
119
151
|
// automatically fetched if needed (causing sessionStore.set() to be called).
|
120
152
|
await result.agent.request('/xrpc/foo.bar')
|
121
153
|
|
122
154
|
// revoke credentials on the server (causing sessionStore.del() to be called)
|
123
|
-
await
|
155
|
+
await agent.signOut()
|
156
|
+
```
|
157
|
+
|
158
|
+
## Advances use-cases
|
159
|
+
|
160
|
+
### Listening for session updates and deletion
|
161
|
+
|
162
|
+
The `OAuthClient` will emit events whenever a session is updated or deleted.
|
163
|
+
|
164
|
+
```ts
|
165
|
+
import {
|
166
|
+
Session,
|
167
|
+
TokenRefreshError,
|
168
|
+
TokenRevokedError,
|
169
|
+
} from '@atproto/oauth-client'
|
170
|
+
|
171
|
+
client.addEventListener('updated', (event: CustomEvent<Session>) => {
|
172
|
+
console.log('Refreshed tokens were saved in the store:', event.detail)
|
173
|
+
})
|
174
|
+
|
175
|
+
client.addEventListener(
|
176
|
+
'deleted',
|
177
|
+
(
|
178
|
+
event: CustomEvent<{
|
179
|
+
sub: string
|
180
|
+
cause: TokenRefreshError | TokenRevokedError | unknown
|
181
|
+
}>,
|
182
|
+
) => {
|
183
|
+
console.log('Session was deleted from the session store:', event.detail)
|
184
|
+
|
185
|
+
const { cause } = event.detail
|
186
|
+
|
187
|
+
if (cause instanceof TokenRefreshError) {
|
188
|
+
// - refresh_token unavailable or expired
|
189
|
+
// - oauth response error (`cause.cause instanceof OAuthResponseError`)
|
190
|
+
// - session data does not match expected values returned by the OAuth server
|
191
|
+
} else if (cause instanceof TokenRevokedError) {
|
192
|
+
// Session was revoked through:
|
193
|
+
// - agent.signOut()
|
194
|
+
// - client.revoke(sub)
|
195
|
+
} else {
|
196
|
+
// An unexpected error occurred, causing the session to be deleted
|
197
|
+
}
|
198
|
+
},
|
199
|
+
)
|
124
200
|
```
|
201
|
+
|
202
|
+
### Force user to re-authenticate
|
203
|
+
|
204
|
+
```ts
|
205
|
+
const url = await client.authorize(handle, {
|
206
|
+
prompt: 'login',
|
207
|
+
state,
|
208
|
+
})
|
209
|
+
```
|
210
|
+
|
211
|
+
or
|
212
|
+
|
213
|
+
```ts
|
214
|
+
const url = await client.authorize(handle, {
|
215
|
+
state,
|
216
|
+
max_age: 600, // Require re-authentication after 10 minutes
|
217
|
+
})
|
218
|
+
```
|
219
|
+
|
220
|
+
### Silent Sign-In
|
221
|
+
|
222
|
+
Using silent sign-in requires to handle retries on the callback endpoint.
|
223
|
+
|
224
|
+
```ts
|
225
|
+
async function createLoginUrl(handle: string, state?: string): string {
|
226
|
+
return client.authorize(handle, {
|
227
|
+
state,
|
228
|
+
// Use "prompt=none" to attempt silent sign-in
|
229
|
+
prompt: 'none',
|
230
|
+
})
|
231
|
+
}
|
232
|
+
|
233
|
+
async function handleCallback(params: URLSearchParams) {
|
234
|
+
try {
|
235
|
+
return await client.callback(params)
|
236
|
+
} catch (err) {
|
237
|
+
// Silent sign-in failed, retry without prompt=none
|
238
|
+
if (
|
239
|
+
err instanceof OAuthCallbackError &&
|
240
|
+
['login_required', 'consent_required'].includes(err.params.get('error'))
|
241
|
+
) {
|
242
|
+
// Do *not* use prompt=none when retrying (to avoid infinite redirects)
|
243
|
+
const url = await client.authorize(handle, { state: err.state })
|
244
|
+
|
245
|
+
// Allow calling code to catch the error and redirect the user to the new URL
|
246
|
+
return new MyLoginRequiredError(url)
|
247
|
+
}
|
248
|
+
|
249
|
+
throw err
|
250
|
+
}
|
251
|
+
}
|
252
|
+
```
|
253
|
+
|
254
|
+
[ATPROTO]: https://atproto.com/ 'AT Protocol'
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"token-invalid-error.d.ts","sourceRoot":"","sources":["../../src/errors/token-invalid-error.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,GAAG,EAAE,MAAM;gBAAX,GAAG,EAAE,MAAM,EAC3B,OAAO,SAAwC,EAC/C,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAIhC"}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.TokenInvalidError = void 0;
|
4
|
+
class TokenInvalidError extends Error {
|
5
|
+
constructor(sub, message = `The session for "${sub}" is invalid`, options) {
|
6
|
+
super(message, options);
|
7
|
+
Object.defineProperty(this, "sub", {
|
8
|
+
enumerable: true,
|
9
|
+
configurable: true,
|
10
|
+
writable: true,
|
11
|
+
value: sub
|
12
|
+
});
|
13
|
+
}
|
14
|
+
}
|
15
|
+
exports.TokenInvalidError = TokenInvalidError;
|
16
|
+
//# sourceMappingURL=token-invalid-error.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"token-invalid-error.js","sourceRoot":"","sources":["../../src/errors/token-invalid-error.ts"],"names":[],"mappings":";;;AAAA,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YACkB,GAAW,EAC3B,OAAO,GAAG,oBAAoB,GAAG,cAAc,EAC/C,OAA6B;QAE7B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAJvB;;;;mBAAgB,GAAG;WAAQ;IAK7B,CAAC;CACF;AARD,8CAQC"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"token-refresh-error.d.ts","sourceRoot":"","sources":["../../src/errors/token-refresh-error.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,GAAG,EAAE,MAAM;gBAAX,GAAG,EAAE,MAAM,EAC3B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAIhC"}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.TokenRefreshError = void 0;
|
4
|
+
class TokenRefreshError extends Error {
|
5
|
+
constructor(sub, message, options) {
|
6
|
+
super(message, options);
|
7
|
+
Object.defineProperty(this, "sub", {
|
8
|
+
enumerable: true,
|
9
|
+
configurable: true,
|
10
|
+
writable: true,
|
11
|
+
value: sub
|
12
|
+
});
|
13
|
+
}
|
14
|
+
}
|
15
|
+
exports.TokenRefreshError = TokenRefreshError;
|
16
|
+
//# sourceMappingURL=token-refresh-error.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"token-refresh-error.js","sourceRoot":"","sources":["../../src/errors/token-refresh-error.ts"],"names":[],"mappings":";;;AAAA,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YACkB,GAAW,EAC3B,OAAe,EACf,OAA6B;QAE7B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAJvB;;;;mBAAgB,GAAG;WAAQ;IAK7B,CAAC;CACF;AARD,8CAQC"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"token-revoked-error.d.ts","sourceRoot":"","sources":["../../src/errors/token-revoked-error.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,GAAG,EAAE,MAAM;gBAAX,GAAG,EAAE,MAAM,EAC3B,OAAO,SAAsD,EAC7D,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAIhC"}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.TokenRevokedError = void 0;
|
4
|
+
class TokenRevokedError extends Error {
|
5
|
+
constructor(sub, message = `The session for "${sub}" was successfully revoked`, options) {
|
6
|
+
super(message, options);
|
7
|
+
Object.defineProperty(this, "sub", {
|
8
|
+
enumerable: true,
|
9
|
+
configurable: true,
|
10
|
+
writable: true,
|
11
|
+
value: sub
|
12
|
+
});
|
13
|
+
}
|
14
|
+
}
|
15
|
+
exports.TokenRevokedError = TokenRevokedError;
|
16
|
+
//# sourceMappingURL=token-revoked-error.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"token-revoked-error.js","sourceRoot":"","sources":["../../src/errors/token-revoked-error.ts"],"names":[],"mappings":";;;AAAA,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YACkB,GAAW,EAC3B,OAAO,GAAG,oBAAoB,GAAG,4BAA4B,EAC7D,OAA6B;QAE7B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAJvB;;;;mBAAgB,GAAG;WAAQ;IAK7B,CAAC;CACF;AARD,8CAQC"}
|
package/dist/index.d.ts
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
export * from '@atproto-labs/did-resolver';
|
1
2
|
export { FetchError, FetchRequestError, FetchResponseError, } from '@atproto-labs/fetch';
|
3
|
+
export * from '@atproto-labs/handle-resolver';
|
4
|
+
export * from '@atproto/did';
|
5
|
+
export * from '@atproto/oauth-types';
|
2
6
|
export * from './oauth-agent.js';
|
3
7
|
export * from './oauth-authorization-server-metadata-resolver.js';
|
4
8
|
export * from './oauth-callback-error.js';
|
@@ -8,8 +12,11 @@ export * from './oauth-resolver-error.js';
|
|
8
12
|
export * from './oauth-response-error.js';
|
9
13
|
export * from './oauth-server-agent.js';
|
10
14
|
export * from './oauth-server-factory.js';
|
11
|
-
export * from './refresh-error.js';
|
12
15
|
export * from './runtime-implementation.js';
|
13
16
|
export * from './session-getter.js';
|
17
|
+
export * from './state-store.js';
|
14
18
|
export * from './types.js';
|
19
|
+
export * from './errors/token-invalid-error.js';
|
20
|
+
export * from './errors/token-refresh-error.js';
|
21
|
+
export * from './errors/token-revoked-error.js';
|
15
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
@@ -1 +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,
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAC5B,cAAc,+BAA+B,CAAA;AAE7C,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AAEpC,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,6BAA6B,CAAA;AAC3C,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAE1B,cAAc,iCAAiC,CAAA;AAC/C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,iCAAiC,CAAA"}
|
package/dist/index.js
CHANGED
@@ -15,10 +15,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
15
15
|
};
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
17
17
|
exports.FetchResponseError = exports.FetchRequestError = exports.FetchError = void 0;
|
18
|
+
__exportStar(require("@atproto-labs/did-resolver"), exports);
|
18
19
|
var fetch_1 = require("@atproto-labs/fetch");
|
19
20
|
Object.defineProperty(exports, "FetchError", { enumerable: true, get: function () { return fetch_1.FetchError; } });
|
20
21
|
Object.defineProperty(exports, "FetchRequestError", { enumerable: true, get: function () { return fetch_1.FetchRequestError; } });
|
21
22
|
Object.defineProperty(exports, "FetchResponseError", { enumerable: true, get: function () { return fetch_1.FetchResponseError; } });
|
23
|
+
__exportStar(require("@atproto-labs/handle-resolver"), exports);
|
24
|
+
__exportStar(require("@atproto/did"), exports);
|
25
|
+
__exportStar(require("@atproto/oauth-types"), exports);
|
22
26
|
__exportStar(require("./oauth-agent.js"), exports);
|
23
27
|
__exportStar(require("./oauth-authorization-server-metadata-resolver.js"), exports);
|
24
28
|
__exportStar(require("./oauth-callback-error.js"), exports);
|
@@ -28,8 +32,11 @@ __exportStar(require("./oauth-resolver-error.js"), exports);
|
|
28
32
|
__exportStar(require("./oauth-response-error.js"), exports);
|
29
33
|
__exportStar(require("./oauth-server-agent.js"), exports);
|
30
34
|
__exportStar(require("./oauth-server-factory.js"), exports);
|
31
|
-
__exportStar(require("./refresh-error.js"), exports);
|
32
35
|
__exportStar(require("./runtime-implementation.js"), exports);
|
33
36
|
__exportStar(require("./session-getter.js"), exports);
|
37
|
+
__exportStar(require("./state-store.js"), exports);
|
34
38
|
__exportStar(require("./types.js"), exports);
|
39
|
+
__exportStar(require("./errors/token-invalid-error.js"), exports);
|
40
|
+
__exportStar(require("./errors/token-refresh-error.js"), exports);
|
41
|
+
__exportStar(require("./errors/token-revoked-error.js"), exports);
|
35
42
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
@@ -1 +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,
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,6DAA0C;AAC1C,6CAI4B;AAH1B,mGAAA,UAAU,OAAA;AACV,0GAAA,iBAAiB,OAAA;AACjB,2GAAA,kBAAkB,OAAA;AAEpB,gEAA6C;AAE7C,+CAA4B;AAC5B,uDAAoC;AAEpC,mDAAgC;AAChC,oFAAiE;AACjE,4DAAyC;AACzC,oDAAiC;AACjC,kFAA+D;AAC/D,4DAAyC;AACzC,4DAAyC;AACzC,0DAAuC;AACvC,4DAAyC;AACzC,8DAA2C;AAC3C,sDAAmC;AACnC,mDAAgC;AAChC,6CAA0B;AAE1B,kEAA+C;AAC/C,kEAA+C;AAC/C,kEAA+C"}
|
package/dist/lock.d.ts
CHANGED
package/dist/lock.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAwBzD,eAAO,MAAM,gBAAgB,EAAE,WAQ9B,CAAA"}
|
package/dist/lock.js
CHANGED
@@ -19,7 +19,7 @@ function acquireLocalLock(name) {
|
|
19
19
|
locks.set(name, next);
|
20
20
|
});
|
21
21
|
}
|
22
|
-
|
22
|
+
const requestLocalLock = (name, fn) => {
|
23
23
|
return acquireLocalLock(name).then(async (release) => {
|
24
24
|
try {
|
25
25
|
return await fn();
|
@@ -28,6 +28,6 @@ function requestLocalLock(name, fn) {
|
|
28
28
|
release();
|
29
29
|
}
|
30
30
|
});
|
31
|
-
}
|
31
|
+
};
|
32
32
|
exports.requestLocalLock = requestLocalLock;
|
33
33
|
//# sourceMappingURL=lock.js.map
|
package/dist/lock.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":";;;
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":";;;AAEA,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;AAEM,MAAM,gBAAgB,GAAgB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE;IACxD,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,CAAA;AARY,QAAA,gBAAgB,oBAQ5B"}
|
@@ -1 +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;
|
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;AAKvE,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;IAYxB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;CA2DvE"}
|
package/dist/oauth-agent.js
CHANGED
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OAuthAgent = void 0;
|
4
4
|
const fetch_1 = require("@atproto-labs/fetch");
|
5
5
|
const jwk_1 = require("@atproto/jwk");
|
6
|
+
const token_invalid_error_js_1 = require("./errors/token-invalid-error.js");
|
7
|
+
const token_revoked_error_js_1 = require("./errors/token-revoked-error.js");
|
6
8
|
const fetch_dpop_js_1 = require("./fetch-dpop.js");
|
7
9
|
const ReadableStream = globalThis.ReadableStream;
|
8
10
|
class OAuthAgent {
|
@@ -75,7 +77,7 @@ class OAuthAgent {
|
|
75
77
|
await this.server.revoke(tokenSet.access_token);
|
76
78
|
}
|
77
79
|
finally {
|
78
|
-
await this.sessionGetter.delStored(this.sub);
|
80
|
+
await this.sessionGetter.delStored(this.sub, new token_revoked_error_js_1.TokenRevokedError(this.sub));
|
79
81
|
}
|
80
82
|
}
|
81
83
|
async request(pathname, init) {
|
@@ -90,12 +92,12 @@ class OAuthAgent {
|
|
90
92
|
headers,
|
91
93
|
});
|
92
94
|
// If the token is not expired, we don't need to refresh it
|
93
|
-
if (!
|
95
|
+
if (!isInvalidTokenResponse(initialResponse)) {
|
94
96
|
return initialResponse;
|
95
97
|
}
|
96
98
|
let tokenSetFresh;
|
97
99
|
try {
|
98
|
-
//
|
100
|
+
// Force a refresh
|
99
101
|
tokenSetFresh = await this.getTokenSet(true);
|
100
102
|
}
|
101
103
|
catch (err) {
|
@@ -112,12 +114,15 @@ class OAuthAgent {
|
|
112
114
|
const finalUrl = new URL(pathname, tokenSetFresh.aud);
|
113
115
|
headers.set('Authorization', finalAuth);
|
114
116
|
const finalResponse = await this.dpopFetch(finalUrl, { ...init, headers });
|
115
|
-
//
|
116
|
-
//
|
117
|
-
|
117
|
+
// The token was successfully refreshed, but is still not accepted by the
|
118
|
+
// resource server. This might be due to the resource server not accepting
|
119
|
+
// credentials from the authorization server (e.g. because some migration
|
120
|
+
// occurred). Any ways, there is no point in keeping the session.
|
121
|
+
if (isInvalidTokenResponse(finalResponse)) {
|
118
122
|
// TODO: Is there a "softer" way to handle this, e.g. by marking the
|
119
|
-
// session as "expired"
|
120
|
-
|
123
|
+
// session as "expired" in the session store, allowing the user to trigger
|
124
|
+
// a new login (using login_hint/id_token_hint)?
|
125
|
+
await this.sessionGetter.delStored(this.sub, new token_invalid_error_js_1.TokenInvalidError(this.sub));
|
121
126
|
}
|
122
127
|
return finalResponse;
|
123
128
|
}
|
@@ -127,7 +132,7 @@ exports.OAuthAgent = OAuthAgent;
|
|
127
132
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc6750#section-3}
|
128
133
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc9449#name-resource-server-provided-no}
|
129
134
|
*/
|
130
|
-
function
|
135
|
+
function isInvalidTokenResponse(response) {
|
131
136
|
if (response.status !== 401)
|
132
137
|
return false;
|
133
138
|
const wwwAuth = response.headers.get('WWW-Authenticate');
|
package/dist/oauth-agent.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"oauth-agent.js","sourceRoot":"","sources":["../src/oauth-agent.ts"],"names":[],"mappings":";;;AAAA,+CAAsD;AACtD,sCAA0D;AAG1D,mDAAkD;AAIlD,MAAM,cAAc,GAAG,UAAU,CAAC,cAErB,CAAA;AAEb,MAAa,UAAU;IAGrB,YACkB,MAAwB,EACxB,GAAW,EACV,aAA4B,EAC7C,QAAe,UAAU,CAAC,KAAK;QAH/B;;;;mBAAgB,MAAM;WAAkB;QACxC;;;;mBAAgB,GAAG;WAAQ;QAC3B;;;;mBAAiB,aAAa;WAAe;QALrC;;;;;WAAyB;QAQjC,IAAI,CAAC,SAAS,GAAG,IAAA,gCAAgB,EAAO;YACtC,KAAK,EAAE,IAAA,iBAAS,EAAC,KAAK,CAAC;YACvB,GAAG,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS;YACpC,GAAG,EAAE,MAAM,CAAC,OAAO;YACnB,aAAa,EAAE,MAAM,CAAC,cAAc,CAAC,iCAAiC;YACtE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7C,MAAM,EAAE,MAAM,CAAC,UAAU;YACzB,YAAY,EAAE,KAAK;SACpB,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAAA;IACnC,CAAC;IAEM,KAAK,CAAC,eAAe;QAC1B,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;IACnC,CAAC;IAED;;OAEG;IACO,KAAK,CAAC,WAAW,CAAC,OAAiB;QAC3C,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAC3E,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,KAAK,CAAC,OAAO;QAQX,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;QAEzC,OAAO;YACL,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBACzB,CAAC,CAAC,IAAA,qBAAe,EAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO;gBAC5C,CAAC,CAAC,SAAS;YACb,OAAO,EACL,QAAQ,CAAC,UAAU,IAAI,IAAI;gBACzB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG;YAChE,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,GAAG,EAAE,QAAQ,CAAC,GAAG;SAClB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACzE,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAA;QACjD,CAAC;gBAAS,CAAC;YACT,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;
|
1
|
+
{"version":3,"file":"oauth-agent.js","sourceRoot":"","sources":["../src/oauth-agent.ts"],"names":[],"mappings":"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"}
|