antarctic 0.5.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.
Files changed (132) hide show
  1. package/README.md +252 -0
  2. package/dist/auth.d.ts +19 -11
  3. package/dist/auth.js +16 -23
  4. package/dist/index.d.ts +1 -1
  5. package/dist/providers/42.d.ts +4 -4
  6. package/dist/providers/42.js +9 -8
  7. package/dist/providers/amazon-cognito.d.ts +4 -4
  8. package/dist/providers/amazon-cognito.js +9 -8
  9. package/dist/providers/anilist.d.ts +4 -4
  10. package/dist/providers/anilist.js +10 -9
  11. package/dist/providers/apple.d.ts +3 -3
  12. package/dist/providers/apple.js +8 -7
  13. package/dist/providers/atlassian.d.ts +4 -4
  14. package/dist/providers/atlassian.js +9 -8
  15. package/dist/providers/auth0.d.ts +4 -4
  16. package/dist/providers/auth0.js +9 -8
  17. package/dist/providers/authentik.d.ts +4 -4
  18. package/dist/providers/authentik.js +9 -8
  19. package/dist/providers/autodesk.d.ts +4 -4
  20. package/dist/providers/autodesk.js +9 -8
  21. package/dist/providers/battlenet.d.ts +4 -4
  22. package/dist/providers/battlenet.js +9 -8
  23. package/dist/providers/bitbucket.d.ts +4 -4
  24. package/dist/providers/bitbucket.js +10 -9
  25. package/dist/providers/box.d.ts +4 -4
  26. package/dist/providers/box.js +9 -8
  27. package/dist/providers/bungie.d.ts +4 -4
  28. package/dist/providers/bungie.js +9 -8
  29. package/dist/providers/coinbase.d.ts +4 -4
  30. package/dist/providers/coinbase.js +9 -8
  31. package/dist/providers/discord.d.ts +4 -4
  32. package/dist/providers/discord.js +9 -8
  33. package/dist/providers/donation-alerts.d.ts +4 -4
  34. package/dist/providers/donation-alerts.js +9 -8
  35. package/dist/providers/dribbble.d.ts +4 -4
  36. package/dist/providers/dribbble.js +9 -8
  37. package/dist/providers/dropbox.d.ts +4 -4
  38. package/dist/providers/dropbox.js +9 -8
  39. package/dist/providers/epicgames.d.ts +4 -4
  40. package/dist/providers/epicgames.js +9 -8
  41. package/dist/providers/etsy.d.ts +4 -4
  42. package/dist/providers/etsy.js +8 -7
  43. package/dist/providers/facebook.d.ts +4 -4
  44. package/dist/providers/facebook.js +9 -8
  45. package/dist/providers/figma.d.ts +4 -4
  46. package/dist/providers/figma.js +9 -8
  47. package/dist/providers/gitea.d.ts +4 -4
  48. package/dist/providers/gitea.js +9 -8
  49. package/dist/providers/github.d.ts +4 -4
  50. package/dist/providers/github.js +9 -8
  51. package/dist/providers/gitlab.d.ts +4 -4
  52. package/dist/providers/gitlab.js +9 -8
  53. package/dist/providers/google.d.ts +4 -4
  54. package/dist/providers/google.js +9 -8
  55. package/dist/providers/intuit.d.ts +4 -4
  56. package/dist/providers/intuit.js +9 -8
  57. package/dist/providers/kakao.d.ts +4 -4
  58. package/dist/providers/kakao.js +9 -8
  59. package/dist/providers/keycloak.d.ts +4 -4
  60. package/dist/providers/keycloak.js +9 -8
  61. package/dist/providers/kick.d.ts +4 -4
  62. package/dist/providers/kick.js +9 -8
  63. package/dist/providers/lichess.d.ts +4 -4
  64. package/dist/providers/lichess.js +9 -8
  65. package/dist/providers/line.d.ts +4 -4
  66. package/dist/providers/line.js +9 -8
  67. package/dist/providers/linear.d.ts +4 -4
  68. package/dist/providers/linear.js +9 -8
  69. package/dist/providers/linkedin.d.ts +4 -4
  70. package/dist/providers/linkedin.js +9 -8
  71. package/dist/providers/mastodon.d.ts +4 -4
  72. package/dist/providers/mastodon.js +9 -8
  73. package/dist/providers/mercadolibre.d.ts +4 -4
  74. package/dist/providers/mercadolibre.js +10 -9
  75. package/dist/providers/mercadopago.d.ts +4 -4
  76. package/dist/providers/mercadopago.js +10 -9
  77. package/dist/providers/microsoft-entra-id.d.ts +4 -4
  78. package/dist/providers/microsoft-entra-id.js +9 -8
  79. package/dist/providers/myanimelist.d.ts +4 -4
  80. package/dist/providers/myanimelist.js +10 -9
  81. package/dist/providers/naver.d.ts +4 -4
  82. package/dist/providers/naver.js +10 -9
  83. package/dist/providers/notion.d.ts +4 -4
  84. package/dist/providers/notion.js +10 -9
  85. package/dist/providers/okta.d.ts +4 -4
  86. package/dist/providers/okta.js +9 -8
  87. package/dist/providers/osu.d.ts +4 -4
  88. package/dist/providers/osu.js +9 -8
  89. package/dist/providers/patreon.d.ts +4 -4
  90. package/dist/providers/patreon.js +9 -8
  91. package/dist/providers/polar.d.ts +4 -4
  92. package/dist/providers/polar.js +9 -8
  93. package/dist/providers/reddit.d.ts +4 -4
  94. package/dist/providers/reddit.js +9 -8
  95. package/dist/providers/roblox.d.ts +4 -4
  96. package/dist/providers/roblox.js +9 -8
  97. package/dist/providers/salesforce.d.ts +4 -4
  98. package/dist/providers/salesforce.js +9 -8
  99. package/dist/providers/shikimori.d.ts +4 -4
  100. package/dist/providers/shikimori.js +10 -9
  101. package/dist/providers/slack.d.ts +4 -4
  102. package/dist/providers/slack.js +9 -8
  103. package/dist/providers/spotify.d.ts +4 -4
  104. package/dist/providers/spotify.js +9 -8
  105. package/dist/providers/startgg.d.ts +4 -4
  106. package/dist/providers/startgg.js +8 -7
  107. package/dist/providers/strava.d.ts +4 -4
  108. package/dist/providers/strava.js +9 -8
  109. package/dist/providers/tiktok.d.ts +4 -4
  110. package/dist/providers/tiktok.js +9 -8
  111. package/dist/providers/tiltify.d.ts +4 -4
  112. package/dist/providers/tiltify.js +9 -8
  113. package/dist/providers/tumblr.d.ts +4 -4
  114. package/dist/providers/tumblr.js +9 -8
  115. package/dist/providers/twitch.d.ts +4 -4
  116. package/dist/providers/twitch.js +9 -8
  117. package/dist/providers/twitter.d.ts +4 -4
  118. package/dist/providers/twitter.js +9 -8
  119. package/dist/providers/vk.d.ts +4 -4
  120. package/dist/providers/vk.js +9 -8
  121. package/dist/providers/withings.d.ts +4 -4
  122. package/dist/providers/withings.js +9 -8
  123. package/dist/providers/workos.d.ts +4 -4
  124. package/dist/providers/workos.js +10 -9
  125. package/dist/providers/yahoo.d.ts +4 -4
  126. package/dist/providers/yahoo.js +9 -8
  127. package/dist/providers/yandex.d.ts +4 -4
  128. package/dist/providers/yandex.js +9 -8
  129. package/dist/providers/zoom.d.ts +4 -4
  130. package/dist/providers/zoom.js +9 -8
  131. package/package.json +2 -1
  132. package/readme.md +0 -155
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
@@ -1,23 +1,19 @@
1
+ import type { OAuth2Tokens } from "./oauth2.js";
1
2
  export interface OAuthUser {
2
3
  id: string;
3
4
  name?: string | null;
4
5
  email?: string | null;
5
6
  image?: string | null;
6
7
  raw?: Record<string, unknown>;
7
- }
8
- export interface OAuthStateStore {
9
- get: (key: string) => Promise<any>;
10
- set: (key: string, value: any, options?: {
11
- expires?: number | string;
12
- }) => Promise<any>;
13
- del: (key: string) => Promise<any>;
8
+ accessToken?: string;
9
+ refreshToken?: string | null;
10
+ scopes?: string[] | null;
14
11
  }
15
12
  export interface ProviderOptions {
16
13
  clientId?: string;
17
14
  clientSecret?: string;
18
15
  redirectURI?: string;
19
16
  scopes?: string[];
20
- store: OAuthStateStore;
21
17
  }
22
18
  export declare class OAuthConfigurationError extends Error {
23
19
  }
@@ -35,7 +31,6 @@ export interface AuthConfig {
35
31
  clientSecret: string | null;
36
32
  redirectURI: string | null;
37
33
  scopes: string[] | null;
38
- store: OAuthStateStore;
39
34
  }
40
35
  export declare function resolveProviderOption(explicit: string | undefined, envPrefix: string, envSuffix: string): string | null;
41
36
  export declare function requireProviderOption(explicit: string | undefined, envPrefix: string, envSuffix: string, optionName: string): string;
@@ -50,8 +45,21 @@ export interface StoredOAuthState {
50
45
  nonce?: string;
51
46
  scopes?: string[];
52
47
  }
53
- export declare function saveOAuthState(store: OAuthStateStore, state: string, payload: StoredOAuthState): Promise<void>;
54
- export declare function consumeOAuthState(store: OAuthStateStore, state: string): Promise<StoredOAuthState>;
48
+ export interface AuthorizationRequest {
49
+ url: URL;
50
+ state: string;
51
+ payload: StoredOAuthState;
52
+ }
53
+ export interface SavedOAuthState {
54
+ state: string;
55
+ payload?: StoredOAuthState;
56
+ }
57
+ export declare function resolveOAuthState(state: string, saved: SavedOAuthState): StoredOAuthState;
58
+ export declare function extractOAuthTokens(tokens: OAuth2Tokens): {
59
+ accessToken: string;
60
+ refreshToken: string | null;
61
+ scopes: string[] | null;
62
+ };
55
63
  export type OAuthCallbackQuery = string | URL | URLSearchParams | Record<string, string | string[] | undefined | null>;
56
64
  export declare function parseCallbackQuery(query: OAuthCallbackQuery): {
57
65
  code: string;
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("Unknown or expired OAuth state");
8
+ super("OAuth state does not match the saved state");
9
9
  }
10
10
  }
11
11
  export class OAuthProviderError extends Error {
@@ -57,39 +57,32 @@ export function resolveAuthConfig(envPrefix, options, requirements) {
57
57
  scopes = envScopes.split(/[\s,]+/).filter((scope) => scope !== "");
58
58
  }
59
59
  }
60
- if (options.store === undefined) {
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 with a 'store'");
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
- const stateKeyPrefix = "arctic:state:";
81
- const stateExpiresSeconds = 60 * 10;
82
- export async function saveOAuthState(store, state, payload) {
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
- await store.del(key);
92
- return payload;
76
+ return saved.payload ?? {};
77
+ }
78
+ // OAuth2Tokens throws on absent fields, and most providers omit the refresh
79
+ // token and scopes unless they were asked for.
80
+ export function extractOAuthTokens(tokens) {
81
+ return {
82
+ accessToken: tokens.accessToken(),
83
+ refreshToken: tokens.hasRefreshToken() ? tokens.refreshToken() : null,
84
+ scopes: tokens.hasScopes() ? tokens.scopes() : null
85
+ };
93
86
  }
94
87
  export function parseCallbackQuery(query) {
95
88
  let params;
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 { OAuthCallbackQuery, OAuthStateStore, OAuthUser, ProviderOptions } from "./auth.js";
70
+ export type { AuthorizationRequest, OAuthCallbackQuery, OAuthUser, ProviderOptions, SavedOAuthState, StoredOAuthState } from "./auth.js";
@@ -1,5 +1,5 @@
1
1
  import type { OAuth2Tokens } from "../oauth2.js";
2
- import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
2
+ import type { AuthorizationRequest, OAuthCallbackQuery, OAuthUser, ProviderOptions, SavedOAuthState } from "../auth.js";
3
3
  export interface FortyTwoOptions extends ProviderOptions {
4
4
  }
5
5
  export declare class FortyTwo {
@@ -7,10 +7,10 @@ export declare class FortyTwo {
7
7
  private clientSecret;
8
8
  private redirectURI;
9
9
  private auth;
10
- constructor(options: FortyTwoOptions);
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
- getAuthorizationURL(scopes?: string[]): Promise<URL>;
15
- getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
14
+ getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
15
+ getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
16
16
  }
@@ -1,5 +1,5 @@
1
1
  import { createOAuth2Request, sendTokenRequest } from "../request.js";
2
- import { consumeOAuthState, fetchUserProfile, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
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,
@@ -52,13 +52,13 @@ export class FortyTwo {
52
52
  const auth = requireAuthConfig(this.auth);
53
53
  const state = generateOAuthState();
54
54
  const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
55
- await saveOAuthState(auth.store, state, {});
56
- return url;
55
+ const payload = {};
56
+ return { url, state, payload };
57
57
  }
58
- async getUser(query) {
59
- const auth = requireAuthConfig(this.auth);
58
+ async getUser(query, saved) {
59
+ requireAuthConfig(this.auth);
60
60
  const { code, state } = parseCallbackQuery(query);
61
- await consumeOAuthState(auth.store, state);
61
+ resolveOAuthState(state, saved);
62
62
  const tokens = await this.validateAuthorizationCode(code);
63
63
  const profile = await fetchUserProfile(userEndpoint, tokens.accessToken());
64
64
  let image = null;
@@ -70,7 +70,8 @@ export class FortyTwo {
70
70
  name: profileString(profile.displayname) ?? profileString(profile.login),
71
71
  email: profileString(profile.email),
72
72
  image,
73
- raw: profile
73
+ raw: profile,
74
+ ...extractOAuthTokens(tokens)
74
75
  };
75
76
  }
76
77
  }
@@ -1,5 +1,5 @@
1
1
  import type { OAuth2Tokens } from "../oauth2.js";
2
- import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
2
+ import type { AuthorizationRequest, OAuthCallbackQuery, OAuthUser, ProviderOptions, SavedOAuthState } from "../auth.js";
3
3
  export interface AmazonCognitoOptions extends ProviderOptions {
4
4
  domain?: string;
5
5
  }
@@ -10,12 +10,12 @@ export declare class AmazonCognito {
10
10
  private userinfoEndpoint;
11
11
  private client;
12
12
  private auth;
13
- constructor(options: AmazonCognitoOptions);
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
- getAuthorizationURL(scopes?: string[]): Promise<URL>;
20
- getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
19
+ getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
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 { consumeOAuthState, fetchUserProfile, generateOAuthCodeVerifier, generateOAuthState, InvalidOAuthCallbackError, parseCallbackQuery, profileId, profileString, requireAuthConfig, requireProviderOption, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
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 });
@@ -46,13 +46,13 @@ export class AmazonCognito {
46
46
  const state = generateOAuthState();
47
47
  const codeVerifier = generateOAuthCodeVerifier();
48
48
  const url = await this.createAuthorizationURL(state, codeVerifier, resolveScopes(scopes, auth, defaultScopes));
49
- await saveOAuthState(auth.store, state, { codeVerifier });
50
- return url;
49
+ const payload = { codeVerifier };
50
+ return { url, state, payload };
51
51
  }
52
- async getUser(query) {
53
- const auth = requireAuthConfig(this.auth);
52
+ async getUser(query, saved) {
53
+ requireAuthConfig(this.auth);
54
54
  const { code, state } = parseCallbackQuery(query);
55
- const stored = await consumeOAuthState(auth.store, state);
55
+ const stored = resolveOAuthState(state, saved);
56
56
  if (typeof stored.codeVerifier !== "string") {
57
57
  throw new InvalidOAuthCallbackError("Missing PKCE code verifier for OAuth state");
58
58
  }
@@ -71,7 +71,8 @@ export class AmazonCognito {
71
71
  profileString(claims.username),
72
72
  email: profileString(claims.email),
73
73
  image: profileString(claims.picture),
74
- raw: claims
74
+ raw: claims,
75
+ ...extractOAuthTokens(tokens)
75
76
  };
76
77
  }
77
78
  }
@@ -1,14 +1,14 @@
1
1
  import type { OAuth2Tokens } from "../oauth2.js";
2
- import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
2
+ import type { AuthorizationRequest, OAuthCallbackQuery, OAuthUser, ProviderOptions, SavedOAuthState } from "../auth.js";
3
3
  export interface AniListOptions extends ProviderOptions {
4
4
  }
5
5
  export declare class AniList {
6
6
  private client;
7
7
  private auth;
8
- constructor(options: AniListOptions);
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
- getAuthorizationURL(): Promise<URL>;
13
- getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
12
+ getAuthorizationURL(): Promise<AuthorizationRequest>;
13
+ getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
14
14
  }
@@ -1,5 +1,5 @@
1
1
  import { OAuth2Client } from "../client.js";
2
- import { consumeOAuthState, generateOAuthState, OAuthProviderError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, saveOAuthState } from "../auth.js";
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,16 +28,16 @@ export class AniList {
28
28
  return tokens;
29
29
  }
30
30
  async getAuthorizationURL() {
31
- const auth = requireAuthConfig(this.auth);
31
+ requireAuthConfig(this.auth);
32
32
  const state = generateOAuthState();
33
33
  const url = this.createAuthorizationURL(state);
34
- await saveOAuthState(auth.store, state, {});
35
- return url;
34
+ const payload = {};
35
+ return { url, state, payload };
36
36
  }
37
- async getUser(query) {
38
- const auth = requireAuthConfig(this.auth);
37
+ async getUser(query, saved) {
38
+ requireAuthConfig(this.auth);
39
39
  const { code, state } = parseCallbackQuery(query);
40
- await consumeOAuthState(auth.store, state);
40
+ resolveOAuthState(state, saved);
41
41
  const tokens = await this.validateAuthorizationCode(code);
42
42
  const viewer = await fetchViewer(tokens.accessToken());
43
43
  let image = null;
@@ -49,7 +49,8 @@ export class AniList {
49
49
  name: profileString(viewer.name),
50
50
  email: null,
51
51
  image,
52
- raw: viewer
52
+ raw: viewer,
53
+ ...extractOAuthTokens(tokens)
53
54
  };
54
55
  }
55
56
  }
@@ -1,5 +1,5 @@
1
1
  import type { OAuth2Tokens } from "../oauth2.js";
2
- import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
2
+ import type { AuthorizationRequest, OAuthCallbackQuery, OAuthUser, ProviderOptions, SavedOAuthState } from "../auth.js";
3
3
  export interface AppleOptions extends ProviderOptions {
4
4
  teamId?: string;
5
5
  keyId?: string;
@@ -16,7 +16,7 @@ export declare class Apple {
16
16
  constructor(clientId: string, teamId: string, keyId: string, pkcs8PrivateKey: Uint8Array, redirectURI: string);
17
17
  createAuthorizationURL(state: string, scopes: string[]): URL;
18
18
  validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
19
- getAuthorizationURL(scopes?: string[]): Promise<URL>;
20
- getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
19
+ getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
20
+ getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
21
21
  private createClientSecret;
22
22
  }
@@ -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 { consumeOAuthState, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, requireProviderOption, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
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";
@@ -62,13 +62,13 @@ export class Apple {
62
62
  if (resolvedScopes.length > 0) {
63
63
  url.searchParams.set("response_mode", "form_post");
64
64
  }
65
- await saveOAuthState(auth.store, state, {});
66
- return url;
65
+ const payload = {};
66
+ return { url, state, payload };
67
67
  }
68
- async getUser(query) {
69
- const auth = requireAuthConfig(this.auth);
68
+ async getUser(query, saved) {
69
+ requireAuthConfig(this.auth);
70
70
  const { code, state } = parseCallbackQuery(query);
71
- await consumeOAuthState(auth.store, state);
71
+ resolveOAuthState(state, saved);
72
72
  const tokens = await this.validateAuthorizationCode(code);
73
73
  const claims = decodeIdToken(tokens.idToken());
74
74
  return {
@@ -76,7 +76,8 @@ export class Apple {
76
76
  name: null,
77
77
  email: profileString(claims.email),
78
78
  image: null,
79
- raw: claims
79
+ raw: claims,
80
+ ...extractOAuthTokens(tokens)
80
81
  };
81
82
  }
82
83
  async createClientSecret() {
@@ -1,5 +1,5 @@
1
1
  import type { OAuth2Tokens } from "../oauth2.js";
2
- import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
2
+ import type { AuthorizationRequest, OAuthCallbackQuery, OAuthUser, ProviderOptions, SavedOAuthState } from "../auth.js";
3
3
  export interface AtlassianOptions extends ProviderOptions {
4
4
  }
5
5
  export declare class Atlassian {
@@ -7,11 +7,11 @@ export declare class Atlassian {
7
7
  private clientSecret;
8
8
  private redirectURI;
9
9
  private auth;
10
- constructor(options: AtlassianOptions);
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
- getAuthorizationURL(scopes?: string[]): Promise<URL>;
16
- getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
15
+ getAuthorizationURL(scopes?: string[]): Promise<AuthorizationRequest>;
16
+ getUser(query: OAuthCallbackQuery, saved: SavedOAuthState): Promise<OAuthUser>;
17
17
  }