antarctic 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +252 -0
- package/dist/auth.d.ts +1 -12
- package/dist/auth.js +7 -34
- package/dist/index.d.ts +1 -1
- package/dist/providers/42.d.ts +2 -2
- package/dist/providers/42.js +4 -5
- package/dist/providers/amazon-cognito.d.ts +2 -2
- package/dist/providers/amazon-cognito.js +4 -5
- package/dist/providers/anilist.d.ts +2 -2
- package/dist/providers/anilist.js +5 -6
- package/dist/providers/apple.d.ts +1 -1
- package/dist/providers/apple.js +3 -4
- package/dist/providers/atlassian.d.ts +2 -2
- package/dist/providers/atlassian.js +4 -5
- package/dist/providers/auth0.d.ts +2 -2
- package/dist/providers/auth0.js +4 -5
- package/dist/providers/authentik.d.ts +2 -2
- package/dist/providers/authentik.js +4 -5
- package/dist/providers/autodesk.d.ts +2 -2
- package/dist/providers/autodesk.js +4 -5
- package/dist/providers/battlenet.d.ts +2 -2
- package/dist/providers/battlenet.js +4 -5
- package/dist/providers/bitbucket.d.ts +2 -2
- package/dist/providers/bitbucket.js +5 -6
- package/dist/providers/box.d.ts +2 -2
- package/dist/providers/box.js +4 -5
- package/dist/providers/bungie.d.ts +2 -2
- package/dist/providers/bungie.js +4 -5
- package/dist/providers/coinbase.d.ts +2 -2
- package/dist/providers/coinbase.js +4 -5
- package/dist/providers/discord.d.ts +2 -2
- package/dist/providers/discord.js +4 -5
- package/dist/providers/donation-alerts.d.ts +2 -2
- package/dist/providers/donation-alerts.js +4 -5
- package/dist/providers/dribbble.d.ts +2 -2
- package/dist/providers/dribbble.js +4 -5
- package/dist/providers/dropbox.d.ts +2 -2
- package/dist/providers/dropbox.js +4 -5
- package/dist/providers/epicgames.d.ts +2 -2
- package/dist/providers/epicgames.js +4 -5
- package/dist/providers/etsy.d.ts +2 -2
- package/dist/providers/etsy.js +3 -4
- package/dist/providers/facebook.d.ts +2 -2
- package/dist/providers/facebook.js +4 -5
- package/dist/providers/figma.d.ts +2 -2
- package/dist/providers/figma.js +4 -5
- package/dist/providers/gitea.d.ts +2 -2
- package/dist/providers/gitea.js +4 -5
- package/dist/providers/github.d.ts +2 -2
- package/dist/providers/github.js +4 -5
- package/dist/providers/gitlab.d.ts +2 -2
- package/dist/providers/gitlab.js +4 -5
- package/dist/providers/google.d.ts +2 -2
- package/dist/providers/google.js +4 -5
- package/dist/providers/intuit.d.ts +2 -2
- package/dist/providers/intuit.js +4 -5
- package/dist/providers/kakao.d.ts +2 -2
- package/dist/providers/kakao.js +4 -5
- package/dist/providers/keycloak.d.ts +2 -2
- package/dist/providers/keycloak.js +4 -5
- package/dist/providers/kick.d.ts +2 -2
- package/dist/providers/kick.js +4 -5
- package/dist/providers/lichess.d.ts +2 -2
- package/dist/providers/lichess.js +4 -5
- package/dist/providers/line.d.ts +2 -2
- package/dist/providers/line.js +4 -5
- package/dist/providers/linear.d.ts +2 -2
- package/dist/providers/linear.js +4 -5
- package/dist/providers/linkedin.d.ts +2 -2
- package/dist/providers/linkedin.js +4 -5
- package/dist/providers/mastodon.d.ts +2 -2
- package/dist/providers/mastodon.js +4 -5
- package/dist/providers/mercadolibre.d.ts +2 -2
- package/dist/providers/mercadolibre.js +5 -6
- package/dist/providers/mercadopago.d.ts +2 -2
- package/dist/providers/mercadopago.js +5 -6
- package/dist/providers/microsoft-entra-id.d.ts +2 -2
- package/dist/providers/microsoft-entra-id.js +4 -5
- package/dist/providers/myanimelist.d.ts +2 -2
- package/dist/providers/myanimelist.js +5 -6
- package/dist/providers/naver.d.ts +2 -2
- package/dist/providers/naver.js +5 -6
- package/dist/providers/notion.d.ts +2 -2
- package/dist/providers/notion.js +5 -6
- package/dist/providers/okta.d.ts +2 -2
- package/dist/providers/okta.js +4 -5
- package/dist/providers/osu.d.ts +2 -2
- package/dist/providers/osu.js +4 -5
- package/dist/providers/patreon.d.ts +2 -2
- package/dist/providers/patreon.js +4 -5
- package/dist/providers/polar.d.ts +2 -2
- package/dist/providers/polar.js +4 -5
- package/dist/providers/reddit.d.ts +2 -2
- package/dist/providers/reddit.js +4 -5
- package/dist/providers/roblox.d.ts +2 -2
- package/dist/providers/roblox.js +4 -5
- package/dist/providers/salesforce.d.ts +2 -2
- package/dist/providers/salesforce.js +4 -5
- package/dist/providers/shikimori.d.ts +2 -2
- package/dist/providers/shikimori.js +5 -6
- package/dist/providers/slack.d.ts +2 -2
- package/dist/providers/slack.js +4 -5
- package/dist/providers/spotify.d.ts +2 -2
- package/dist/providers/spotify.js +4 -5
- package/dist/providers/startgg.d.ts +2 -2
- package/dist/providers/startgg.js +3 -4
- package/dist/providers/strava.d.ts +2 -2
- package/dist/providers/strava.js +4 -5
- package/dist/providers/tiktok.d.ts +2 -2
- package/dist/providers/tiktok.js +4 -5
- package/dist/providers/tiltify.d.ts +2 -2
- package/dist/providers/tiltify.js +4 -5
- package/dist/providers/tumblr.d.ts +2 -2
- package/dist/providers/tumblr.js +4 -5
- package/dist/providers/twitch.d.ts +2 -2
- package/dist/providers/twitch.js +4 -5
- package/dist/providers/twitter.d.ts +2 -2
- package/dist/providers/twitter.js +4 -5
- package/dist/providers/vk.d.ts +2 -2
- package/dist/providers/vk.js +4 -5
- package/dist/providers/withings.d.ts +2 -2
- package/dist/providers/withings.js +4 -5
- package/dist/providers/workos.d.ts +2 -2
- package/dist/providers/workos.js +5 -6
- package/dist/providers/yahoo.d.ts +2 -2
- package/dist/providers/yahoo.js +4 -5
- package/dist/providers/yandex.d.ts +2 -2
- package/dist/providers/yandex.js +4 -5
- package/dist/providers/zoom.d.ts +2 -2
- package/dist/providers/zoom.js +4 -5
- package/package.json +2 -1
- package/readme.md +0 -165
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Antarctic
|
|
2
|
+
|
|
3
|
+
Antarctic is a fork of [Arctic](https://arcticjs.dev) by [pilcrowOnPaper](https://github.com/pilcrowOnPaper), adding a high level auth layer on top of its OAuth 2.0 clients. Only the authorization code flow is supported. Built on top of the Fetch API, it's light weight, fully-typed, and runtime-agnostic.
|
|
4
|
+
|
|
5
|
+
Read the documentation at [antarcticjs.dev](https://antarcticjs.dev).
|
|
6
|
+
|
|
7
|
+
All of the OAuth 2.0 clients and provider coverage are Arctic's work. If you only need those, use [Arctic](https://arcticjs.dev) directly. See [credits](#credits).
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npm install antarctic
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## High-level API
|
|
14
|
+
|
|
15
|
+
Every provider except Synology has two methods that run the whole sign-in flow: `getAuthorizationURL()` starts it and `getUser()` finishes it in your callback route. Antarctic keeps nothing in between: you hold the `state` and `payload` from the first call, usually in a signed cookie, and pass them to the second.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import * as auth from "antarctic";
|
|
19
|
+
|
|
20
|
+
const github = new auth.GitHub();
|
|
21
|
+
|
|
22
|
+
// Login route
|
|
23
|
+
const { url, state, payload } = await github.getAuthorizationURL();
|
|
24
|
+
setCookie("oauth", JSON.stringify({ state, payload }), { httpOnly: true, maxAge: 600 });
|
|
25
|
+
return Response.redirect(url);
|
|
26
|
+
|
|
27
|
+
// Callback route
|
|
28
|
+
const user = await github.getUser(request.url, JSON.parse(getCookie("oauth")));
|
|
29
|
+
// { id: "1", name: "The Octocat", email: "octocat@github.com", image: "https://...", ... }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Options
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
new auth.GitHub({ clientId, clientSecret, redirectURI, scopes });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Every option is optional. A missing one falls back to an environment variable named after the provider, then to the provider default:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
GITHUB_CLIENT_ID
|
|
42
|
+
GITHUB_CLIENT_SECRET
|
|
43
|
+
GITHUB_REDIRECT_URI
|
|
44
|
+
GITHUB_SCOPES
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The environment is read when the provider is constructed, so load your `.env` file first. Some providers take extra options, such as Auth0's `domain` (`AUTH0_DOMAIN`). Apple always needs `{ pkcs8PrivateKey }`, which has no environment variable.
|
|
48
|
+
|
|
49
|
+
### `getAuthorizationURL(scopes?)`
|
|
50
|
+
|
|
51
|
+
Generates a fresh `state` and, where the provider uses PKCE, a code verifier. It returns:
|
|
52
|
+
|
|
53
|
+
- `url`: where to redirect the user.
|
|
54
|
+
- `state`: the CSRF token.
|
|
55
|
+
- `payload`: whatever `getUser()` needs later, such as the PKCE verifier. Keep it as it is.
|
|
56
|
+
|
|
57
|
+
### `getUser(query, { state, payload })`
|
|
58
|
+
|
|
59
|
+
Takes the callback query (a full URL, a query string, a `URLSearchParams`, or a plain object) and the `state` and `payload` you kept. It checks your `state` against the one in the query, exchanges the code, fetches the profile, and returns the same shape for every provider:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
{
|
|
63
|
+
(id, name, email, image, raw, accessToken, refreshToken, scopes);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`name`, `email`, and `image` are `null` when the provider does not expose them. `raw` is the provider's own profile, for the fields this shape does not cover. `scopes` are the ones the provider actually granted, or `null` if it does not say.
|
|
68
|
+
|
|
69
|
+
Delete the saved state once you read it, so it cannot be used twice.
|
|
70
|
+
|
|
71
|
+
### Scopes
|
|
72
|
+
|
|
73
|
+
Scopes are set per provider and can be overridden per login. From highest to lowest priority:
|
|
74
|
+
|
|
75
|
+
1. The argument to `getAuthorizationURL(scopes)`, for that login only.
|
|
76
|
+
2. The `scopes` option, for every login with that provider.
|
|
77
|
+
3. `GITHUB_SCOPES`, separated by commas, whitespace, or both.
|
|
78
|
+
4. The provider default, the minimal set that yields a full profile.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const github = new auth.GitHub({ scopes: ["read:user", "user:email"] });
|
|
82
|
+
|
|
83
|
+
await github.getAuthorizationURL(); // read:user user:email
|
|
84
|
+
await github.getAuthorizationURL(["read:user", "user:email", "repo"]); // this login only
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
An override replaces the list instead of adding to it, so repeat the scopes you still need. An empty array requests none. AniList, Bitbucket, MercadoLibre, MercadoPago, MyAnimeList, Naver, Notion, Shikimori, and WorkOS take their scopes from the app settings and ignore all of the above.
|
|
88
|
+
|
|
89
|
+
### Errors
|
|
90
|
+
|
|
91
|
+
- `OAuthConfigurationError`: a required option is missing from both the constructor and the environment, or a high-level method was called on a provider built with the positional constructor.
|
|
92
|
+
- `InvalidOAuthCallbackError`: the callback query has no `code` or `state`, or the `payload` lacks a PKCE verifier the provider needs.
|
|
93
|
+
- `InvalidOAuthStateError`: the saved `state` does not match the one in the callback query.
|
|
94
|
+
- `OAuthProviderError`: the provider returned an error, or a profile that cannot be used. `error.code` holds its error code when it sent one.
|
|
95
|
+
|
|
96
|
+
Sessions, cookies, and your user database remain your responsibility: take the returned user and plug it into your framework of choice. See the [documentation](https://antarcticjs.dev/high-level-api) for the details.
|
|
97
|
+
|
|
98
|
+
## Low-level API
|
|
99
|
+
|
|
100
|
+
Arctic's low level API remains available on the same objects, including the positional constructors. It is unchanged except that PKCE providers build the URL asynchronously, so `createAuthorizationURL()` returns a promise for them:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import * as arctic from "antarctic";
|
|
104
|
+
|
|
105
|
+
const github = new arctic.GitHub(clientId, clientSecret, redirectURI);
|
|
106
|
+
|
|
107
|
+
const state = arctic.generateState();
|
|
108
|
+
const scopes = ["user:email"];
|
|
109
|
+
const authorizationURL = github.createAuthorizationURL(state, scopes);
|
|
110
|
+
|
|
111
|
+
// ...
|
|
112
|
+
|
|
113
|
+
const tokens = await github.validateAuthorizationCode(code);
|
|
114
|
+
const accessToken = tokens.accessToken();
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
See the [low-level API](https://antarcticjs.dev/low-level-api) docs for the full flow.
|
|
118
|
+
|
|
119
|
+
> Antarctic only supports providers that follow the OAuth 2.0 spec (including PKCE and token revocation).
|
|
120
|
+
|
|
121
|
+
## Compare to Arctic
|
|
122
|
+
|
|
123
|
+
Arctic gives you the OAuth primitives and leaves the flow to you: generating the state and PKCE verifier, checking the callback, and fetching and mapping the profile for each provider. Antarctic does all of that in two calls and returns the same user shape for every provider. Here is Google, which uses PKCE, in Arctic:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import * as arctic from "arctic";
|
|
127
|
+
// import * as arctic from "antarctic"; // Exactly the same for the low-level API
|
|
128
|
+
|
|
129
|
+
const google = new arctic.Google(clientId, clientSecret, redirectURI);
|
|
130
|
+
|
|
131
|
+
// Login route
|
|
132
|
+
const state = arctic.generateState();
|
|
133
|
+
const codeVerifier = arctic.generateCodeVerifier();
|
|
134
|
+
const scopes = ["openid", "profile", "email"];
|
|
135
|
+
const url = await google.createAuthorizationURL(state, codeVerifier, scopes);
|
|
136
|
+
setCookie("state", state, { httpOnly: true, maxAge: 600 });
|
|
137
|
+
setCookie("code_verifier", codeVerifier, { httpOnly: true, maxAge: 600 });
|
|
138
|
+
return Response.redirect(url);
|
|
139
|
+
|
|
140
|
+
// Callback route
|
|
141
|
+
const params = new URL(request.url).searchParams;
|
|
142
|
+
const code = params.get("code");
|
|
143
|
+
if (code === null || params.get("state") !== getCookie("state")) {
|
|
144
|
+
throw new Error("Invalid request");
|
|
145
|
+
}
|
|
146
|
+
const tokens = await google.validateAuthorizationCode(code, getCookie("code_verifier"));
|
|
147
|
+
const claims = arctic.decodeIdToken(tokens.idToken());
|
|
148
|
+
// Map the claims to your own user shape, or fetch the profile for non-OIDC providers
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
And in Antarctic:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import * as auth from "antarctic";
|
|
155
|
+
|
|
156
|
+
const google = new auth.Google();
|
|
157
|
+
|
|
158
|
+
// Login route
|
|
159
|
+
const { url, state, payload } = await google.getAuthorizationURL();
|
|
160
|
+
setCookie("oauth", JSON.stringify({ state, payload }), { httpOnly: true, maxAge: 600 });
|
|
161
|
+
return Response.redirect(url);
|
|
162
|
+
|
|
163
|
+
// Callback route
|
|
164
|
+
const user = await google.getUser(request.url, JSON.parse(getCookie("oauth")));
|
|
165
|
+
// { id, name, email, image, raw, accessToken, refreshToken, scopes }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
| | Arctic | Antarctic |
|
|
169
|
+
| ----------------------------- | --------------------- | --------------------------------- |
|
|
170
|
+
| Credentials | Positional arguments | Environment or options |
|
|
171
|
+
| State and PKCE verifier | You generate them | Generated for you |
|
|
172
|
+
| Scopes | You pass them | Per-provider default, overridable |
|
|
173
|
+
| Callback query and CSRF check | You parse and compare | Done in `getUser()` |
|
|
174
|
+
| User profile | You fetch and map it | Normalized user with the tokens |
|
|
175
|
+
|
|
176
|
+
## Credits
|
|
177
|
+
|
|
178
|
+
Antarctic is a fork of [Arctic](https://github.com/pilcrowonpaper/arctic), created and maintained by [pilcrowOnPaper](https://github.com/pilcrowOnPaper). The OAuth 2.0 clients, the provider implementations, the docs those pages grew from, and the design that makes all of it consistent are their work. Antarctic adds one layer on top: `getAuthorizationURL()`, `getUser()`, and the option resolution around them.
|
|
179
|
+
|
|
180
|
+
Arctic is MIT licensed. Antarctic keeps that license and the original copyright notice, and adds its own for the new work. See [LICENSE](./LICENSE).
|
|
181
|
+
|
|
182
|
+
If you only need the OAuth 2.0 clients without the high level layer, use [Arctic](https://arcticjs.dev) directly. Please report provider issues that are not specific to Antarctic's additions upstream, where they benefit everyone.
|
|
183
|
+
|
|
184
|
+
## Semver
|
|
185
|
+
|
|
186
|
+
Antarctic does not strictly follow semantic versioning. While we aim to only introduce breaking changes in major versions, we may introduce them in a minor update if a provider updates their API in a non-backward compatible way. However, they will never be introduced in a patch update.
|
|
187
|
+
|
|
188
|
+
## Supported providers
|
|
189
|
+
|
|
190
|
+
- 42 School
|
|
191
|
+
- Amazon Cognito
|
|
192
|
+
- AniList
|
|
193
|
+
- Apple
|
|
194
|
+
- Atlassian
|
|
195
|
+
- Auth0
|
|
196
|
+
- Authentik
|
|
197
|
+
- Autodesk Platform Services
|
|
198
|
+
- Battle.net
|
|
199
|
+
- Bitbucket
|
|
200
|
+
- Box
|
|
201
|
+
- Bungie
|
|
202
|
+
- Coinbase
|
|
203
|
+
- Discord
|
|
204
|
+
- DonationAlerts
|
|
205
|
+
- Dribbble
|
|
206
|
+
- Dropbox
|
|
207
|
+
- Etsy
|
|
208
|
+
- Epic Games
|
|
209
|
+
- Facebook
|
|
210
|
+
- Figma
|
|
211
|
+
- Gitea
|
|
212
|
+
- GitHub
|
|
213
|
+
- GitLab
|
|
214
|
+
- Google
|
|
215
|
+
- Intuit
|
|
216
|
+
- Kakao
|
|
217
|
+
- KeyCloak
|
|
218
|
+
- Kick
|
|
219
|
+
- Lichess
|
|
220
|
+
- Line
|
|
221
|
+
- Linear
|
|
222
|
+
- LinkedIn
|
|
223
|
+
- Mastodon
|
|
224
|
+
- MercadoLibre
|
|
225
|
+
- MercadoPago
|
|
226
|
+
- Microsoft Entra ID
|
|
227
|
+
- MyAnimeList
|
|
228
|
+
- Naver
|
|
229
|
+
- Notion
|
|
230
|
+
- Okta
|
|
231
|
+
- osu!
|
|
232
|
+
- Patreon
|
|
233
|
+
- Polar
|
|
234
|
+
- Reddit
|
|
235
|
+
- Roblox
|
|
236
|
+
- Salesforce
|
|
237
|
+
- Shikimori
|
|
238
|
+
- Slack
|
|
239
|
+
- Spotify
|
|
240
|
+
- Start.gg
|
|
241
|
+
- Strava
|
|
242
|
+
- Synology
|
|
243
|
+
- TikTok
|
|
244
|
+
- Tiltify
|
|
245
|
+
- Tumblr
|
|
246
|
+
- Twitch
|
|
247
|
+
- Twitter
|
|
248
|
+
- VK
|
|
249
|
+
- WorkOS
|
|
250
|
+
- Yahoo
|
|
251
|
+
- Yandex
|
|
252
|
+
- Zoom
|
package/dist/auth.d.ts
CHANGED
|
@@ -9,19 +9,11 @@ export interface OAuthUser {
|
|
|
9
9
|
refreshToken?: string | null;
|
|
10
10
|
scopes?: string[] | null;
|
|
11
11
|
}
|
|
12
|
-
export interface OAuthStateStore {
|
|
13
|
-
get: (key: string) => Promise<any>;
|
|
14
|
-
set: (key: string, value: any, options?: {
|
|
15
|
-
expires?: number | string;
|
|
16
|
-
}) => Promise<any>;
|
|
17
|
-
del: (key: string) => Promise<any>;
|
|
18
|
-
}
|
|
19
12
|
export interface ProviderOptions {
|
|
20
13
|
clientId?: string;
|
|
21
14
|
clientSecret?: string;
|
|
22
15
|
redirectURI?: string;
|
|
23
16
|
scopes?: string[];
|
|
24
|
-
store: OAuthStateStore;
|
|
25
17
|
}
|
|
26
18
|
export declare class OAuthConfigurationError extends Error {
|
|
27
19
|
}
|
|
@@ -39,7 +31,6 @@ export interface AuthConfig {
|
|
|
39
31
|
clientSecret: string | null;
|
|
40
32
|
redirectURI: string | null;
|
|
41
33
|
scopes: string[] | null;
|
|
42
|
-
store: OAuthStateStore;
|
|
43
34
|
}
|
|
44
35
|
export declare function resolveProviderOption(explicit: string | undefined, envPrefix: string, envSuffix: string): string | null;
|
|
45
36
|
export declare function requireProviderOption(explicit: string | undefined, envPrefix: string, envSuffix: string, optionName: string): string;
|
|
@@ -54,8 +45,6 @@ export interface StoredOAuthState {
|
|
|
54
45
|
nonce?: string;
|
|
55
46
|
scopes?: string[];
|
|
56
47
|
}
|
|
57
|
-
export declare function saveOAuthState(store: OAuthStateStore, state: string, payload: StoredOAuthState): Promise<void>;
|
|
58
|
-
export declare function consumeOAuthState(store: OAuthStateStore, state: string): Promise<StoredOAuthState>;
|
|
59
48
|
export interface AuthorizationRequest {
|
|
60
49
|
url: URL;
|
|
61
50
|
state: string;
|
|
@@ -65,7 +54,7 @@ export interface SavedOAuthState {
|
|
|
65
54
|
state: string;
|
|
66
55
|
payload?: StoredOAuthState;
|
|
67
56
|
}
|
|
68
|
-
export declare function resolveOAuthState(
|
|
57
|
+
export declare function resolveOAuthState(state: string, saved: SavedOAuthState): StoredOAuthState;
|
|
69
58
|
export declare function extractOAuthTokens(tokens: OAuth2Tokens): {
|
|
70
59
|
accessToken: string;
|
|
71
60
|
refreshToken: string | null;
|
package/dist/auth.js
CHANGED
|
@@ -5,7 +5,7 @@ export class InvalidOAuthCallbackError extends Error {
|
|
|
5
5
|
}
|
|
6
6
|
export class InvalidOAuthStateError extends Error {
|
|
7
7
|
constructor() {
|
|
8
|
-
super("
|
|
8
|
+
super("OAuth state does not match the saved state");
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
export class OAuthProviderError extends Error {
|
|
@@ -57,50 +57,23 @@ export function resolveAuthConfig(envPrefix, options, requirements) {
|
|
|
57
57
|
scopes = envScopes.split(/[\s,]+/).filter((scope) => scope !== "");
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
throw new OAuthConfigurationError("Missing 'store': pass a polystore-compatible store");
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
clientId,
|
|
65
|
-
clientSecret,
|
|
66
|
-
redirectURI,
|
|
67
|
-
scopes,
|
|
68
|
-
store: options.store
|
|
69
|
-
};
|
|
60
|
+
return { clientId, clientSecret, redirectURI, scopes };
|
|
70
61
|
}
|
|
71
62
|
export function requireAuthConfig(auth) {
|
|
72
63
|
if (auth === null) {
|
|
73
|
-
throw new OAuthConfigurationError("getAuthorizationURL() and getUser() require the options constructor
|
|
64
|
+
throw new OAuthConfigurationError("getAuthorizationURL() and getUser() require the options constructor");
|
|
74
65
|
}
|
|
75
66
|
return auth;
|
|
76
67
|
}
|
|
77
68
|
export function resolveScopes(argument, auth, defaultScopes) {
|
|
78
69
|
return argument ?? auth.scopes ?? defaultScopes;
|
|
79
70
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
await store.set(stateKeyPrefix + state, payload, { expires: stateExpiresSeconds });
|
|
84
|
-
}
|
|
85
|
-
export async function consumeOAuthState(store, state) {
|
|
86
|
-
const key = stateKeyPrefix + state;
|
|
87
|
-
const payload = await store.get(key);
|
|
88
|
-
if (typeof payload !== "object" || payload === null) {
|
|
71
|
+
// Comparing the saved state against the one the provider echoed back is the CSRF check.
|
|
72
|
+
export function resolveOAuthState(state, saved) {
|
|
73
|
+
if (saved?.state !== state) {
|
|
89
74
|
throw new InvalidOAuthStateError();
|
|
90
75
|
}
|
|
91
|
-
|
|
92
|
-
return payload;
|
|
93
|
-
}
|
|
94
|
-
// With `saved` the caller kept the state itself, so comparing it against the
|
|
95
|
-
// value the provider echoed back is the CSRF check. Otherwise the store is.
|
|
96
|
-
export async function resolveOAuthState(store, state, saved) {
|
|
97
|
-
if (saved !== undefined) {
|
|
98
|
-
if (saved.state !== state) {
|
|
99
|
-
throw new InvalidOAuthStateError();
|
|
100
|
-
}
|
|
101
|
-
return saved.payload ?? {};
|
|
102
|
-
}
|
|
103
|
-
return await consumeOAuthState(store, state);
|
|
76
|
+
return saved.payload ?? {};
|
|
104
77
|
}
|
|
105
78
|
// OAuth2Tokens throws on absent fields, and most providers omit the refresh
|
|
106
79
|
// token and scopes unless they were asked for.
|
package/dist/index.d.ts
CHANGED
|
@@ -67,4 +67,4 @@ export { OAuth2Tokens, generateCodeVerifier, generateState } from "./oauth2.js";
|
|
|
67
67
|
export { OAuth2RequestError, ArcticFetchError, UnexpectedErrorResponseBodyError, UnexpectedResponseError } from "./request.js";
|
|
68
68
|
export { decodeIdToken } from "./oidc.js";
|
|
69
69
|
export { InvalidOAuthCallbackError, InvalidOAuthStateError, OAuthConfigurationError, OAuthProviderError } from "./auth.js";
|
|
70
|
-
export type { AuthorizationRequest, OAuthCallbackQuery,
|
|
70
|
+
export type { AuthorizationRequest, OAuthCallbackQuery, OAuthUser, ProviderOptions, SavedOAuthState, StoredOAuthState } from "./auth.js";
|
package/dist/providers/42.d.ts
CHANGED
|
@@ -7,10 +7,10 @@ export declare class FortyTwo {
|
|
|
7
7
|
private clientSecret;
|
|
8
8
|
private redirectURI;
|
|
9
9
|
private auth;
|
|
10
|
-
constructor(options
|
|
10
|
+
constructor(options?: FortyTwoOptions);
|
|
11
11
|
constructor(clientId: string, clientSecret: string, redirectURI: string);
|
|
12
12
|
createAuthorizationURL(state: string, scopes: string[]): URL;
|
|
13
13
|
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
14
14
|
getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
|
|
15
|
-
getUser(query: OAuthCallbackQuery, saved
|
|
15
|
+
getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
|
|
16
16
|
}
|
package/dist/providers/42.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createOAuth2Request, sendTokenRequest } from "../request.js";
|
|
2
|
-
import { extractOAuthTokens, fetchUserProfile, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveOAuthState, resolveScopes
|
|
2
|
+
import { extractOAuthTokens, fetchUserProfile, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveOAuthState, resolveScopes } from "../auth.js";
|
|
3
3
|
const authorizationEndpoint = "https://api.intra.42.fr/oauth/authorize";
|
|
4
4
|
const tokenEndpoint = "https://api.intra.42.fr/oauth/token";
|
|
5
5
|
const userEndpoint = "https://api.intra.42.fr/v2/me";
|
|
@@ -10,7 +10,7 @@ export class FortyTwo {
|
|
|
10
10
|
clientSecret;
|
|
11
11
|
redirectURI;
|
|
12
12
|
auth = null;
|
|
13
|
-
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
13
|
+
constructor(clientIdOrOptions = {}, clientSecret, redirectURI) {
|
|
14
14
|
if (typeof clientIdOrOptions === "object") {
|
|
15
15
|
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
|
|
16
16
|
clientSecret: true,
|
|
@@ -53,13 +53,12 @@ export class FortyTwo {
|
|
|
53
53
|
const state = generateOAuthState();
|
|
54
54
|
const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
|
|
55
55
|
const payload = {};
|
|
56
|
-
await saveOAuthState(auth.store, state, payload);
|
|
57
56
|
return { url, state, payload };
|
|
58
57
|
}
|
|
59
58
|
async getUser(query, saved) {
|
|
60
|
-
|
|
59
|
+
requireAuthConfig(this.auth);
|
|
61
60
|
const { code, state } = parseCallbackQuery(query);
|
|
62
|
-
|
|
61
|
+
resolveOAuthState(state, saved);
|
|
63
62
|
const tokens = await this.validateAuthorizationCode(code);
|
|
64
63
|
const profile = await fetchUserProfile(userEndpoint, tokens.accessToken());
|
|
65
64
|
let image = null;
|
|
@@ -10,12 +10,12 @@ export declare class AmazonCognito {
|
|
|
10
10
|
private userinfoEndpoint;
|
|
11
11
|
private client;
|
|
12
12
|
private auth;
|
|
13
|
-
constructor(options
|
|
13
|
+
constructor(options?: AmazonCognitoOptions);
|
|
14
14
|
constructor(domain: string, clientId: string, clientSecret: string | null, redirectURI: string);
|
|
15
15
|
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): Promise<URL>;
|
|
16
16
|
validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;
|
|
17
17
|
refreshAccessToken(refreshToken: string, scopes: string[]): Promise<OAuth2Tokens>;
|
|
18
18
|
revokeToken(token: string): Promise<void>;
|
|
19
19
|
getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
|
|
20
|
-
getUser(query: OAuthCallbackQuery, saved
|
|
20
|
+
getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
|
|
21
21
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CodeChallengeMethod, OAuth2Client } from "../client.js";
|
|
2
2
|
import { decodeIdToken } from "../oidc.js";
|
|
3
|
-
import { extractOAuthTokens, fetchUserProfile, generateOAuthCodeVerifier, generateOAuthState, InvalidOAuthCallbackError, parseCallbackQuery, profileId, profileString, requireAuthConfig, requireProviderOption, resolveAuthConfig, resolveOAuthState, resolveScopes
|
|
3
|
+
import { extractOAuthTokens, fetchUserProfile, generateOAuthCodeVerifier, generateOAuthState, InvalidOAuthCallbackError, parseCallbackQuery, profileId, profileString, requireAuthConfig, requireProviderOption, resolveAuthConfig, resolveOAuthState, resolveScopes } from "../auth.js";
|
|
4
4
|
const envPrefix = "AMAZON_COGNITO";
|
|
5
5
|
const defaultScopes = ["openid", "profile", "email"];
|
|
6
6
|
export class AmazonCognito {
|
|
@@ -10,7 +10,7 @@ export class AmazonCognito {
|
|
|
10
10
|
userinfoEndpoint;
|
|
11
11
|
client;
|
|
12
12
|
auth = null;
|
|
13
|
-
constructor(domainOrOptions, clientId, clientSecret, redirectURI) {
|
|
13
|
+
constructor(domainOrOptions = {}, clientId, clientSecret, redirectURI) {
|
|
14
14
|
let domain;
|
|
15
15
|
if (typeof domainOrOptions === "object") {
|
|
16
16
|
this.auth = resolveAuthConfig(envPrefix, domainOrOptions, { redirectURI: true });
|
|
@@ -47,13 +47,12 @@ export class AmazonCognito {
|
|
|
47
47
|
const codeVerifier = generateOAuthCodeVerifier();
|
|
48
48
|
const url = await this.createAuthorizationURL(state, codeVerifier, resolveScopes(scopes, auth, defaultScopes));
|
|
49
49
|
const payload = { codeVerifier };
|
|
50
|
-
await saveOAuthState(auth.store, state, payload);
|
|
51
50
|
return { url, state, payload };
|
|
52
51
|
}
|
|
53
52
|
async getUser(query, saved) {
|
|
54
|
-
|
|
53
|
+
requireAuthConfig(this.auth);
|
|
55
54
|
const { code, state } = parseCallbackQuery(query);
|
|
56
|
-
const stored =
|
|
55
|
+
const stored = resolveOAuthState(state, saved);
|
|
57
56
|
if (typeof stored.codeVerifier !== "string") {
|
|
58
57
|
throw new InvalidOAuthCallbackError("Missing PKCE code verifier for OAuth state");
|
|
59
58
|
}
|
|
@@ -5,10 +5,10 @@ export interface AniListOptions extends ProviderOptions {
|
|
|
5
5
|
export declare class AniList {
|
|
6
6
|
private client;
|
|
7
7
|
private auth;
|
|
8
|
-
constructor(options
|
|
8
|
+
constructor(options?: AniListOptions);
|
|
9
9
|
constructor(clientId: string, clientSecret: string, redirectURI: string);
|
|
10
10
|
createAuthorizationURL(state: string): URL;
|
|
11
11
|
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
12
12
|
getAuthorizationURL(): Promise<AuthorizationRequest>;
|
|
13
|
-
getUser(query: OAuthCallbackQuery, saved
|
|
13
|
+
getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
|
|
14
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OAuth2Client } from "../client.js";
|
|
2
|
-
import { extractOAuthTokens, generateOAuthState, OAuthProviderError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveOAuthState
|
|
2
|
+
import { extractOAuthTokens, generateOAuthState, OAuthProviderError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveOAuthState } from "../auth.js";
|
|
3
3
|
const authorizationEndpoint = "https://anilist.co/api/v2/oauth/authorize";
|
|
4
4
|
const tokenEndpoint = "https://anilist.co/api/v2/oauth/token";
|
|
5
5
|
const graphqlEndpoint = "https://graphql.anilist.co";
|
|
@@ -7,7 +7,7 @@ const envPrefix = "ANI_LIST";
|
|
|
7
7
|
export class AniList {
|
|
8
8
|
client;
|
|
9
9
|
auth = null;
|
|
10
|
-
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
10
|
+
constructor(clientIdOrOptions = {}, clientSecret, redirectURI) {
|
|
11
11
|
if (typeof clientIdOrOptions === "object") {
|
|
12
12
|
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
|
|
13
13
|
clientSecret: true,
|
|
@@ -28,17 +28,16 @@ export class AniList {
|
|
|
28
28
|
return tokens;
|
|
29
29
|
}
|
|
30
30
|
async getAuthorizationURL() {
|
|
31
|
-
|
|
31
|
+
requireAuthConfig(this.auth);
|
|
32
32
|
const state = generateOAuthState();
|
|
33
33
|
const url = this.createAuthorizationURL(state);
|
|
34
34
|
const payload = {};
|
|
35
|
-
await saveOAuthState(auth.store, state, payload);
|
|
36
35
|
return { url, state, payload };
|
|
37
36
|
}
|
|
38
37
|
async getUser(query, saved) {
|
|
39
|
-
|
|
38
|
+
requireAuthConfig(this.auth);
|
|
40
39
|
const { code, state } = parseCallbackQuery(query);
|
|
41
|
-
|
|
40
|
+
resolveOAuthState(state, saved);
|
|
42
41
|
const tokens = await this.validateAuthorizationCode(code);
|
|
43
42
|
const viewer = await fetchViewer(tokens.accessToken());
|
|
44
43
|
let image = null;
|
|
@@ -17,6 +17,6 @@ export declare class Apple {
|
|
|
17
17
|
createAuthorizationURL(state: string, scopes: string[]): URL;
|
|
18
18
|
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
19
19
|
getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
|
|
20
|
-
getUser(query: OAuthCallbackQuery, saved
|
|
20
|
+
getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
|
|
21
21
|
private createClientSecret;
|
|
22
22
|
}
|
package/dist/providers/apple.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createJWTSignatureMessage, encodeJWT } from "../jwt.js";
|
|
2
2
|
import { createOAuth2Request, sendTokenRequest } from "../request.js";
|
|
3
3
|
import { decodeIdToken } from "../oidc.js";
|
|
4
|
-
import { extractOAuthTokens, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, requireProviderOption, resolveAuthConfig, resolveOAuthState, resolveScopes
|
|
4
|
+
import { extractOAuthTokens, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, requireProviderOption, resolveAuthConfig, resolveOAuthState, resolveScopes } from "../auth.js";
|
|
5
5
|
const authorizationEndpoint = "https://appleid.apple.com/auth/authorize";
|
|
6
6
|
const tokenEndpoint = "https://appleid.apple.com/auth/token";
|
|
7
7
|
const envPrefix = "APPLE";
|
|
@@ -63,13 +63,12 @@ export class Apple {
|
|
|
63
63
|
url.searchParams.set("response_mode", "form_post");
|
|
64
64
|
}
|
|
65
65
|
const payload = {};
|
|
66
|
-
await saveOAuthState(auth.store, state, payload);
|
|
67
66
|
return { url, state, payload };
|
|
68
67
|
}
|
|
69
68
|
async getUser(query, saved) {
|
|
70
|
-
|
|
69
|
+
requireAuthConfig(this.auth);
|
|
71
70
|
const { code, state } = parseCallbackQuery(query);
|
|
72
|
-
|
|
71
|
+
resolveOAuthState(state, saved);
|
|
73
72
|
const tokens = await this.validateAuthorizationCode(code);
|
|
74
73
|
const claims = decodeIdToken(tokens.idToken());
|
|
75
74
|
return {
|
|
@@ -7,11 +7,11 @@ export declare class Atlassian {
|
|
|
7
7
|
private clientSecret;
|
|
8
8
|
private redirectURI;
|
|
9
9
|
private auth;
|
|
10
|
-
constructor(options
|
|
10
|
+
constructor(options?: AtlassianOptions);
|
|
11
11
|
constructor(clientId: string, clientSecret: string, redirectURI: string);
|
|
12
12
|
createAuthorizationURL(state: string, scopes: string[]): URL;
|
|
13
13
|
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
14
14
|
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
|
|
15
15
|
getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
|
|
16
|
-
getUser(query: OAuthCallbackQuery, saved
|
|
16
|
+
getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
|
|
17
17
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createOAuth2Request, sendTokenRequest } from "../request.js";
|
|
2
|
-
import { extractOAuthTokens, fetchUserProfile, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveOAuthState, resolveScopes
|
|
2
|
+
import { extractOAuthTokens, fetchUserProfile, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveOAuthState, resolveScopes } from "../auth.js";
|
|
3
3
|
const authorizationEndpoint = "https://auth.atlassian.com/authorize";
|
|
4
4
|
const tokenEndpoint = "https://auth.atlassian.com/oauth/token";
|
|
5
5
|
const userEndpoint = "https://api.atlassian.com/me";
|
|
@@ -10,7 +10,7 @@ export class Atlassian {
|
|
|
10
10
|
clientSecret;
|
|
11
11
|
redirectURI;
|
|
12
12
|
auth = null;
|
|
13
|
-
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
13
|
+
constructor(clientIdOrOptions = {}, clientSecret, redirectURI) {
|
|
14
14
|
if (typeof clientIdOrOptions === "object") {
|
|
15
15
|
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
|
|
16
16
|
clientSecret: true,
|
|
@@ -65,13 +65,12 @@ export class Atlassian {
|
|
|
65
65
|
const state = generateOAuthState();
|
|
66
66
|
const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
|
|
67
67
|
const payload = {};
|
|
68
|
-
await saveOAuthState(auth.store, state, payload);
|
|
69
68
|
return { url, state, payload };
|
|
70
69
|
}
|
|
71
70
|
async getUser(query, saved) {
|
|
72
|
-
|
|
71
|
+
requireAuthConfig(this.auth);
|
|
73
72
|
const { code, state } = parseCallbackQuery(query);
|
|
74
|
-
|
|
73
|
+
resolveOAuthState(state, saved);
|
|
75
74
|
const tokens = await this.validateAuthorizationCode(code);
|
|
76
75
|
const profile = await fetchUserProfile(userEndpoint, tokens.accessToken());
|
|
77
76
|
return {
|
|
@@ -10,12 +10,12 @@ export declare class Auth0 {
|
|
|
10
10
|
private userinfoEndpoint;
|
|
11
11
|
private client;
|
|
12
12
|
private auth;
|
|
13
|
-
constructor(options
|
|
13
|
+
constructor(options?: Auth0Options);
|
|
14
14
|
constructor(domain: string, clientId: string, clientSecret: string | null, redirectURI: string);
|
|
15
15
|
createAuthorizationURL(state: string, codeVerifier: string | null, scopes: string[]): Promise<URL>;
|
|
16
16
|
validateAuthorizationCode(code: string, codeVerifier: string | null): Promise<OAuth2Tokens>;
|
|
17
17
|
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
|
|
18
18
|
revokeToken(token: string): Promise<void>;
|
|
19
19
|
getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
|
|
20
|
-
getUser(query: OAuthCallbackQuery, saved
|
|
20
|
+
getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
|
|
21
21
|
}
|
package/dist/providers/auth0.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CodeChallengeMethod, OAuth2Client } from "../client.js";
|
|
2
2
|
import { decodeIdToken } from "../oidc.js";
|
|
3
|
-
import { extractOAuthTokens, fetchUserProfile, generateOAuthCodeVerifier, generateOAuthState, InvalidOAuthCallbackError, parseCallbackQuery, profileId, profileString, requireAuthConfig, requireProviderOption, resolveAuthConfig, resolveOAuthState, resolveScopes
|
|
3
|
+
import { extractOAuthTokens, fetchUserProfile, generateOAuthCodeVerifier, generateOAuthState, InvalidOAuthCallbackError, parseCallbackQuery, profileId, profileString, requireAuthConfig, requireProviderOption, resolveAuthConfig, resolveOAuthState, resolveScopes } from "../auth.js";
|
|
4
4
|
const envPrefix = "AUTH0";
|
|
5
5
|
const defaultScopes = ["openid", "profile", "email"];
|
|
6
6
|
export class Auth0 {
|
|
@@ -10,7 +10,7 @@ export class Auth0 {
|
|
|
10
10
|
userinfoEndpoint;
|
|
11
11
|
client;
|
|
12
12
|
auth = null;
|
|
13
|
-
constructor(domainOrOptions, clientId, clientSecret, redirectURI) {
|
|
13
|
+
constructor(domainOrOptions = {}, clientId, clientSecret, redirectURI) {
|
|
14
14
|
let domain;
|
|
15
15
|
if (typeof domainOrOptions === "object") {
|
|
16
16
|
this.auth = resolveAuthConfig(envPrefix, domainOrOptions, { redirectURI: true });
|
|
@@ -53,13 +53,12 @@ export class Auth0 {
|
|
|
53
53
|
const codeVerifier = generateOAuthCodeVerifier();
|
|
54
54
|
const url = await this.createAuthorizationURL(state, codeVerifier, resolveScopes(scopes, auth, defaultScopes));
|
|
55
55
|
const payload = { codeVerifier };
|
|
56
|
-
await saveOAuthState(auth.store, state, payload);
|
|
57
56
|
return { url, state, payload };
|
|
58
57
|
}
|
|
59
58
|
async getUser(query, saved) {
|
|
60
|
-
|
|
59
|
+
requireAuthConfig(this.auth);
|
|
61
60
|
const { code, state } = parseCallbackQuery(query);
|
|
62
|
-
const stored =
|
|
61
|
+
const stored = resolveOAuthState(state, saved);
|
|
63
62
|
if (typeof stored.codeVerifier !== "string") {
|
|
64
63
|
throw new InvalidOAuthCallbackError("Missing PKCE code verifier for OAuth state");
|
|
65
64
|
}
|