antarctic 0.2.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/LICENSE +24 -0
- package/README.md +155 -0
- package/dist/auth.d.ts +63 -0
- package/dist/auth.js +191 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.js +105 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +69 -0
- package/dist/oauth2.d.ts +16 -0
- package/dist/oauth2.js +67 -0
- package/dist/oidc.d.ts +1 -0
- package/dist/oidc.js +11 -0
- package/dist/providers/42.d.ts +16 -0
- package/dist/providers/42.js +75 -0
- package/dist/providers/amazon-cognito.d.ts +21 -0
- package/dist/providers/amazon-cognito.js +76 -0
- package/dist/providers/anilist.d.ts +14 -0
- package/dist/providers/anilist.js +91 -0
- package/dist/providers/apple.d.ts +22 -0
- package/dist/providers/apple.js +106 -0
- package/dist/providers/atlassian.d.ts +17 -0
- package/dist/providers/atlassian.js +83 -0
- package/dist/providers/auth0.d.ts +21 -0
- package/dist/providers/auth0.js +80 -0
- package/dist/providers/authentik.d.ts +21 -0
- package/dist/providers/authentik.js +75 -0
- package/dist/providers/autodesk.d.ts +16 -0
- package/dist/providers/autodesk.js +60 -0
- package/dist/providers/battlenet.d.ts +16 -0
- package/dist/providers/battlenet.js +69 -0
- package/dist/providers/bitbucket.d.ts +15 -0
- package/dist/providers/bitbucket.js +79 -0
- package/dist/providers/box.d.ts +18 -0
- package/dist/providers/box.js +90 -0
- package/dist/providers/bungie.d.ts +17 -0
- package/dist/providers/bungie.js +72 -0
- package/dist/providers/coinbase.d.ts +18 -0
- package/dist/providers/coinbase.js +95 -0
- package/dist/providers/discord.d.ts +16 -0
- package/dist/providers/discord.js +68 -0
- package/dist/providers/donation-alerts.d.ts +17 -0
- package/dist/providers/donation-alerts.js +86 -0
- package/dist/providers/dribbble.d.ts +16 -0
- package/dist/providers/dribbble.js +73 -0
- package/dist/providers/dropbox.d.ts +16 -0
- package/dist/providers/dropbox.js +96 -0
- package/dist/providers/epicgames.d.ts +16 -0
- package/dist/providers/epicgames.js +60 -0
- package/dist/providers/etsy.d.ts +15 -0
- package/dist/providers/etsy.js +68 -0
- package/dist/providers/facebook.d.ts +16 -0
- package/dist/providers/facebook.js +80 -0
- package/dist/providers/figma.d.ts +15 -0
- package/dist/providers/figma.js +56 -0
- package/dist/providers/gitea.d.ts +19 -0
- package/dist/providers/gitea.js +62 -0
- package/dist/providers/github.d.ts +17 -0
- package/dist/providers/github.js +142 -0
- package/dist/providers/gitlab.d.ts +21 -0
- package/dist/providers/gitlab.js +64 -0
- package/dist/providers/google.d.ts +16 -0
- package/dist/providers/google.js +70 -0
- package/dist/providers/intuit.d.ts +16 -0
- package/dist/providers/intuit.js +66 -0
- package/dist/providers/kakao.d.ts +17 -0
- package/dist/providers/kakao.js +95 -0
- package/dist/providers/keycloak.d.ts +21 -0
- package/dist/providers/keycloak.js +74 -0
- package/dist/providers/kick.d.ts +18 -0
- package/dist/providers/kick.js +103 -0
- package/dist/providers/lichess.d.ts +14 -0
- package/dist/providers/lichess.js +63 -0
- package/dist/providers/line.d.ts +17 -0
- package/dist/providers/line.js +98 -0
- package/dist/providers/linear.d.ts +16 -0
- package/dist/providers/linear.js +112 -0
- package/dist/providers/linkedin.d.ts +17 -0
- package/dist/providers/linkedin.js +89 -0
- package/dist/providers/mastodon.d.ts +20 -0
- package/dist/providers/mastodon.js +67 -0
- package/dist/providers/mercadolibre.d.ts +17 -0
- package/dist/providers/mercadolibre.js +95 -0
- package/dist/providers/mercadopago.d.ts +17 -0
- package/dist/providers/mercadopago.js +95 -0
- package/dist/providers/microsoft-entra-id.d.ts +20 -0
- package/dist/providers/microsoft-entra-id.js +120 -0
- package/dist/providers/myanimelist.d.ts +15 -0
- package/dist/providers/myanimelist.js +56 -0
- package/dist/providers/naver.d.ts +17 -0
- package/dist/providers/naver.js +83 -0
- package/dist/providers/notion.d.ts +14 -0
- package/dist/providers/notion.js +65 -0
- package/dist/providers/okta.d.ts +22 -0
- package/dist/providers/okta.js +85 -0
- package/dist/providers/osu.d.ts +17 -0
- package/dist/providers/osu.js +82 -0
- package/dist/providers/patreon.d.ts +17 -0
- package/dist/providers/patreon.js +89 -0
- package/dist/providers/polar.d.ts +18 -0
- package/dist/providers/polar.js +100 -0
- package/dist/providers/reddit.d.ts +15 -0
- package/dist/providers/reddit.js +55 -0
- package/dist/providers/roblox.d.ts +16 -0
- package/dist/providers/roblox.js +67 -0
- package/dist/providers/salesforce.d.ts +21 -0
- package/dist/providers/salesforce.js +74 -0
- package/dist/providers/shikimori.d.ts +17 -0
- package/dist/providers/shikimori.js +81 -0
- package/dist/providers/slack.d.ts +14 -0
- package/dist/providers/slack.js +59 -0
- package/dist/providers/spotify.d.ts +15 -0
- package/dist/providers/spotify.js +67 -0
- package/dist/providers/startgg.d.ts +17 -0
- package/dist/providers/startgg.js +143 -0
- package/dist/providers/strava.d.ts +17 -0
- package/dist/providers/strava.js +85 -0
- package/dist/providers/synology.d.ts +9 -0
- package/dist/providers/synology.js +20 -0
- package/dist/providers/tiktok.d.ts +18 -0
- package/dist/providers/tiktok.js +109 -0
- package/dist/providers/tiltify.d.ts +17 -0
- package/dist/providers/tiltify.js +90 -0
- package/dist/providers/tumblr.d.ts +15 -0
- package/dist/providers/tumblr.js +63 -0
- package/dist/providers/twitch.d.ts +17 -0
- package/dist/providers/twitch.js +91 -0
- package/dist/providers/twitter.d.ts +16 -0
- package/dist/providers/twitter.js +67 -0
- package/dist/providers/vk.d.ts +16 -0
- package/dist/providers/vk.js +82 -0
- package/dist/providers/withings.d.ts +16 -0
- package/dist/providers/withings.js +120 -0
- package/dist/providers/workos.d.ts +16 -0
- package/dist/providers/workos.js +82 -0
- package/dist/providers/yahoo.d.ts +15 -0
- package/dist/providers/yahoo.js +65 -0
- package/dist/providers/yandex.d.ts +15 -0
- package/dist/providers/yandex.js +66 -0
- package/dist/providers/zoom.d.ts +16 -0
- package/dist/providers/zoom.js +66 -0
- package/dist/request.d.ts +26 -0
- package/dist/request.js +182 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +20 -0
- package/package.json +42 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OAuth2Tokens } from "../oauth2.js";
|
|
2
|
+
import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
|
|
3
|
+
export interface BungieOptions extends ProviderOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class Bungie {
|
|
7
|
+
private client;
|
|
8
|
+
private apiKey;
|
|
9
|
+
private auth;
|
|
10
|
+
constructor(options: BungieOptions);
|
|
11
|
+
constructor(clientId: string, clientSecret: string | null, redirectURI: string);
|
|
12
|
+
createAuthorizationURL(state: string, scopes: string[]): URL;
|
|
13
|
+
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
14
|
+
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
|
|
15
|
+
getAuthorizationURL(scopes?: string[]): Promise<URL>;
|
|
16
|
+
getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { OAuth2Client } from "../client.js";
|
|
2
|
+
import { consumeOAuthState, fetchUserProfile, generateOAuthState, OAuthConfigurationError, OAuthProviderError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveProviderOption, resolveScopes, saveOAuthState } from "../auth.js";
|
|
3
|
+
const authorizationEndpoint = "https://www.bungie.net/en/oauth/authorize";
|
|
4
|
+
const tokenEndpoint = "https://www.bungie.net/platform/app/oauth/token";
|
|
5
|
+
const userEndpoint = "https://www.bungie.net/platform/User/GetCurrentBungieNetUser/";
|
|
6
|
+
const envPrefix = "BUNGIE";
|
|
7
|
+
// Bungie access is configured on the app, not requested via scopes.
|
|
8
|
+
const defaultScopes = [];
|
|
9
|
+
export class Bungie {
|
|
10
|
+
client;
|
|
11
|
+
apiKey = null;
|
|
12
|
+
auth = null;
|
|
13
|
+
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
14
|
+
if (typeof clientIdOrOptions === "object") {
|
|
15
|
+
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, { redirectURI: true });
|
|
16
|
+
this.apiKey = resolveProviderOption(clientIdOrOptions.apiKey, envPrefix, "API_KEY");
|
|
17
|
+
this.client = new OAuth2Client(this.auth.clientId, this.auth.clientSecret, this.auth.redirectURI);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
this.client = new OAuth2Client(clientIdOrOptions, clientSecret ?? null, redirectURI ?? null);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
createAuthorizationURL(state, scopes) {
|
|
24
|
+
const url = this.client.createAuthorizationURL(authorizationEndpoint, state, scopes);
|
|
25
|
+
return url;
|
|
26
|
+
}
|
|
27
|
+
async validateAuthorizationCode(code) {
|
|
28
|
+
const tokens = await this.client.validateAuthorizationCode(tokenEndpoint, code, null);
|
|
29
|
+
return tokens;
|
|
30
|
+
}
|
|
31
|
+
async refreshAccessToken(refreshToken) {
|
|
32
|
+
const tokens = await this.client.refreshAccessToken(tokenEndpoint, refreshToken, []);
|
|
33
|
+
return tokens;
|
|
34
|
+
}
|
|
35
|
+
async getAuthorizationURL(scopes) {
|
|
36
|
+
const auth = requireAuthConfig(this.auth);
|
|
37
|
+
const state = generateOAuthState();
|
|
38
|
+
const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
|
|
39
|
+
await saveOAuthState(auth.store, state, {});
|
|
40
|
+
return url;
|
|
41
|
+
}
|
|
42
|
+
async getUser(query) {
|
|
43
|
+
const auth = requireAuthConfig(this.auth);
|
|
44
|
+
if (this.apiKey === null) {
|
|
45
|
+
throw new OAuthConfigurationError("Missing 'apiKey': pass it in the constructor options or set BUNGIE_API_KEY");
|
|
46
|
+
}
|
|
47
|
+
const { code, state } = parseCallbackQuery(query);
|
|
48
|
+
await consumeOAuthState(auth.store, state);
|
|
49
|
+
const tokens = await this.validateAuthorizationCode(code);
|
|
50
|
+
const body = await fetchUserProfile(userEndpoint, tokens.accessToken(), {
|
|
51
|
+
"X-API-Key": this.apiKey
|
|
52
|
+
});
|
|
53
|
+
const profile = body.Response;
|
|
54
|
+
if (typeof profile !== "object" || profile === null) {
|
|
55
|
+
throw new OAuthProviderError("Unexpected user profile response body");
|
|
56
|
+
}
|
|
57
|
+
const user = profile;
|
|
58
|
+
const picturePath = profileString(user.profilePicturePath);
|
|
59
|
+
let image = null;
|
|
60
|
+
if (picturePath !== null) {
|
|
61
|
+
image = picturePath.startsWith("http")
|
|
62
|
+
? picturePath
|
|
63
|
+
: `https://www.bungie.net${picturePath.startsWith("/") ? "" : "/"}${picturePath}`;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
id: profileId(user.membershipId),
|
|
67
|
+
name: profileString(user.cachedBungieGlobalDisplayName) ?? profileString(user.displayName),
|
|
68
|
+
email: null,
|
|
69
|
+
image
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OAuth2Tokens } from "../oauth2.js";
|
|
2
|
+
import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
|
|
3
|
+
export interface CoinbaseOptions extends ProviderOptions {
|
|
4
|
+
}
|
|
5
|
+
export declare class Coinbase {
|
|
6
|
+
private clientId;
|
|
7
|
+
private clientSecret;
|
|
8
|
+
private redirectURI;
|
|
9
|
+
private auth;
|
|
10
|
+
constructor(options: CoinbaseOptions);
|
|
11
|
+
constructor(clientId: string, clientSecret: string, redirectURI: string);
|
|
12
|
+
createAuthorizationURL(state: string, scopes: string[]): URL;
|
|
13
|
+
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
14
|
+
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
|
|
15
|
+
revokeToken(token: string): Promise<void>;
|
|
16
|
+
getAuthorizationURL(scopes?: string[]): Promise<URL>;
|
|
17
|
+
getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createOAuth2Request, sendTokenRequest, sendTokenRevocationRequest } from "../request.js";
|
|
2
|
+
import { consumeOAuthState, fetchUserProfile, generateOAuthState, OAuthProviderError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
|
|
3
|
+
const authorizationEndpoint = "https://www.coinbase.com/oauth/authorize";
|
|
4
|
+
const tokenEndpoint = "https://www.coinbase.com/oauth/token";
|
|
5
|
+
const tokenRevocationEndpoint = "https://api.coinbase.com/oauth/revoke";
|
|
6
|
+
const userEndpoint = "https://api.coinbase.com/v2/user";
|
|
7
|
+
const envPrefix = "COINBASE";
|
|
8
|
+
const defaultScopes = ["wallet:user:read", "wallet:user:email"];
|
|
9
|
+
export class Coinbase {
|
|
10
|
+
clientId;
|
|
11
|
+
clientSecret;
|
|
12
|
+
redirectURI;
|
|
13
|
+
auth = null;
|
|
14
|
+
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
15
|
+
if (typeof clientIdOrOptions === "object") {
|
|
16
|
+
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
|
|
17
|
+
clientSecret: true,
|
|
18
|
+
redirectURI: true
|
|
19
|
+
});
|
|
20
|
+
this.clientId = this.auth.clientId;
|
|
21
|
+
this.clientSecret = this.auth.clientSecret ?? "";
|
|
22
|
+
this.redirectURI = this.auth.redirectURI ?? "";
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.clientId = clientIdOrOptions;
|
|
26
|
+
this.clientSecret = clientSecret ?? "";
|
|
27
|
+
this.redirectURI = redirectURI ?? "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
createAuthorizationURL(state, scopes) {
|
|
31
|
+
const url = new URL(authorizationEndpoint);
|
|
32
|
+
url.searchParams.set("response_type", "code");
|
|
33
|
+
url.searchParams.set("client_id", this.clientId);
|
|
34
|
+
url.searchParams.set("state", state);
|
|
35
|
+
if (scopes.length > 0) {
|
|
36
|
+
url.searchParams.set("scope", scopes.join(" "));
|
|
37
|
+
}
|
|
38
|
+
url.searchParams.set("redirect_uri", this.redirectURI);
|
|
39
|
+
return url;
|
|
40
|
+
}
|
|
41
|
+
async validateAuthorizationCode(code) {
|
|
42
|
+
const body = new URLSearchParams();
|
|
43
|
+
body.set("grant_type", "authorization_code");
|
|
44
|
+
body.set("code", code);
|
|
45
|
+
body.set("redirect_uri", this.redirectURI);
|
|
46
|
+
body.set("client_id", this.clientId);
|
|
47
|
+
body.set("client_secret", this.clientSecret);
|
|
48
|
+
const request = createOAuth2Request(tokenEndpoint, body);
|
|
49
|
+
const tokens = await sendTokenRequest(request);
|
|
50
|
+
return tokens;
|
|
51
|
+
}
|
|
52
|
+
async refreshAccessToken(refreshToken) {
|
|
53
|
+
const body = new URLSearchParams();
|
|
54
|
+
body.set("grant_type", "refresh_token");
|
|
55
|
+
body.set("refresh_token", refreshToken);
|
|
56
|
+
body.set("client_id", this.clientId);
|
|
57
|
+
body.set("client_secret", this.clientSecret);
|
|
58
|
+
const request = createOAuth2Request(tokenEndpoint, body);
|
|
59
|
+
const tokens = await sendTokenRequest(request);
|
|
60
|
+
return tokens;
|
|
61
|
+
}
|
|
62
|
+
async revokeToken(token) {
|
|
63
|
+
const body = new URLSearchParams();
|
|
64
|
+
body.set("token", token);
|
|
65
|
+
body.set("client_id", this.clientId);
|
|
66
|
+
body.set("client_secret", this.clientSecret);
|
|
67
|
+
const request = createOAuth2Request(tokenRevocationEndpoint, body);
|
|
68
|
+
await sendTokenRevocationRequest(request);
|
|
69
|
+
}
|
|
70
|
+
async getAuthorizationURL(scopes) {
|
|
71
|
+
const auth = requireAuthConfig(this.auth);
|
|
72
|
+
const state = generateOAuthState();
|
|
73
|
+
const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
|
|
74
|
+
await saveOAuthState(auth.store, state, {});
|
|
75
|
+
return url;
|
|
76
|
+
}
|
|
77
|
+
async getUser(query) {
|
|
78
|
+
const auth = requireAuthConfig(this.auth);
|
|
79
|
+
const { code, state } = parseCallbackQuery(query);
|
|
80
|
+
await consumeOAuthState(auth.store, state);
|
|
81
|
+
const tokens = await this.validateAuthorizationCode(code);
|
|
82
|
+
const body = await fetchUserProfile(userEndpoint, tokens.accessToken());
|
|
83
|
+
const profile = body.data;
|
|
84
|
+
if (typeof profile !== "object" || profile === null) {
|
|
85
|
+
throw new OAuthProviderError("Unexpected user profile response body");
|
|
86
|
+
}
|
|
87
|
+
const user = profile;
|
|
88
|
+
return {
|
|
89
|
+
id: profileId(user.id),
|
|
90
|
+
name: profileString(user.name) ?? profileString(user.username),
|
|
91
|
+
email: profileString(user.email),
|
|
92
|
+
image: profileString(user.avatar_url)
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OAuth2Tokens } from "../oauth2.js";
|
|
2
|
+
import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
|
|
3
|
+
export interface DiscordOptions extends ProviderOptions {
|
|
4
|
+
}
|
|
5
|
+
export declare class Discord {
|
|
6
|
+
private client;
|
|
7
|
+
private auth;
|
|
8
|
+
constructor(options: DiscordOptions);
|
|
9
|
+
constructor(clientId: string, clientSecret: string | null, redirectURI: string);
|
|
10
|
+
createAuthorizationURL(state: string, codeVerifier: string | null, scopes: string[]): URL;
|
|
11
|
+
validateAuthorizationCode(code: string, codeVerifier: string | null): Promise<OAuth2Tokens>;
|
|
12
|
+
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
|
|
13
|
+
revokeToken(token: string): Promise<void>;
|
|
14
|
+
getAuthorizationURL(scopes?: string[]): Promise<URL>;
|
|
15
|
+
getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { CodeChallengeMethod, OAuth2Client } from "../client.js";
|
|
2
|
+
import { consumeOAuthState, fetchUserProfile, generateOAuthCodeVerifier, generateOAuthState, InvalidOAuthCallbackError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
|
|
3
|
+
const authorizationEndpoint = "https://discord.com/oauth2/authorize";
|
|
4
|
+
const tokenEndpoint = "https://discord.com/api/oauth2/token";
|
|
5
|
+
const tokenRevocationEndpoint = "https://discord.com/api/oauth2/token/revoke";
|
|
6
|
+
const userEndpoint = "https://discord.com/api/users/@me";
|
|
7
|
+
const envPrefix = "DISCORD";
|
|
8
|
+
const defaultScopes = ["identify", "email"];
|
|
9
|
+
export class Discord {
|
|
10
|
+
client;
|
|
11
|
+
auth = null;
|
|
12
|
+
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
13
|
+
if (typeof clientIdOrOptions === "object") {
|
|
14
|
+
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, { redirectURI: true });
|
|
15
|
+
this.client = new OAuth2Client(this.auth.clientId, this.auth.clientSecret, this.auth.redirectURI);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
this.client = new OAuth2Client(clientIdOrOptions, clientSecret ?? null, redirectURI ?? null);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
createAuthorizationURL(state, codeVerifier, scopes) {
|
|
22
|
+
let url;
|
|
23
|
+
if (codeVerifier !== null) {
|
|
24
|
+
url = this.client.createAuthorizationURLWithPKCE(authorizationEndpoint, state, CodeChallengeMethod.S256, codeVerifier, scopes);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
url = this.client.createAuthorizationURL(authorizationEndpoint, state, scopes);
|
|
28
|
+
}
|
|
29
|
+
return url;
|
|
30
|
+
}
|
|
31
|
+
async validateAuthorizationCode(code, codeVerifier) {
|
|
32
|
+
const tokens = await this.client.validateAuthorizationCode(tokenEndpoint, code, codeVerifier);
|
|
33
|
+
return tokens;
|
|
34
|
+
}
|
|
35
|
+
async refreshAccessToken(refreshToken) {
|
|
36
|
+
const tokens = await this.client.refreshAccessToken(tokenEndpoint, refreshToken, []);
|
|
37
|
+
return tokens;
|
|
38
|
+
}
|
|
39
|
+
async revokeToken(token) {
|
|
40
|
+
await this.client.revokeToken(tokenRevocationEndpoint, token);
|
|
41
|
+
}
|
|
42
|
+
async getAuthorizationURL(scopes) {
|
|
43
|
+
const auth = requireAuthConfig(this.auth);
|
|
44
|
+
const state = generateOAuthState();
|
|
45
|
+
const codeVerifier = generateOAuthCodeVerifier();
|
|
46
|
+
const url = this.createAuthorizationURL(state, codeVerifier, resolveScopes(scopes, auth, defaultScopes));
|
|
47
|
+
await saveOAuthState(auth.store, state, { codeVerifier });
|
|
48
|
+
return url;
|
|
49
|
+
}
|
|
50
|
+
async getUser(query) {
|
|
51
|
+
const auth = requireAuthConfig(this.auth);
|
|
52
|
+
const { code, state } = parseCallbackQuery(query);
|
|
53
|
+
const stored = await consumeOAuthState(auth.store, state);
|
|
54
|
+
if (typeof stored.codeVerifier !== "string") {
|
|
55
|
+
throw new InvalidOAuthCallbackError("Missing PKCE code verifier for OAuth state");
|
|
56
|
+
}
|
|
57
|
+
const tokens = await this.validateAuthorizationCode(code, stored.codeVerifier);
|
|
58
|
+
const profile = await fetchUserProfile(userEndpoint, tokens.accessToken());
|
|
59
|
+
const id = profileId(profile.id);
|
|
60
|
+
const avatar = profileString(profile.avatar);
|
|
61
|
+
return {
|
|
62
|
+
id,
|
|
63
|
+
name: profileString(profile.global_name) ?? profileString(profile.username),
|
|
64
|
+
email: profileString(profile.email),
|
|
65
|
+
image: avatar === null ? null : `https://cdn.discordapp.com/avatars/${id}/${avatar}.png`
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OAuth2Tokens } from "../oauth2.js";
|
|
2
|
+
import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
|
|
3
|
+
export interface DonationAlertsOptions extends ProviderOptions {
|
|
4
|
+
}
|
|
5
|
+
export declare class DonationAlerts {
|
|
6
|
+
private clientId;
|
|
7
|
+
private clientSecret;
|
|
8
|
+
private redirectURI;
|
|
9
|
+
private auth;
|
|
10
|
+
constructor(options: DonationAlertsOptions);
|
|
11
|
+
constructor(clientId: string, clientSecret: string, redirectURI: string);
|
|
12
|
+
createAuthorizationURL(scopes: string[]): URL;
|
|
13
|
+
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
14
|
+
refreshAccessToken(refreshToken: string, scopes: string[]): Promise<OAuth2Tokens>;
|
|
15
|
+
getAuthorizationURL(scopes?: string[]): Promise<URL>;
|
|
16
|
+
getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createOAuth2Request, sendTokenRequest } from "../request.js";
|
|
2
|
+
import { consumeOAuthState, fetchUserProfile, generateOAuthState, OAuthProviderError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
|
|
3
|
+
const authorizationEndpoint = "https://www.donationalerts.com/oauth/authorize";
|
|
4
|
+
const tokenEndpoint = "https://www.donationalerts.com/oauth/token";
|
|
5
|
+
const userEndpoint = "https://www.donationalerts.com/api/v1/user/oauth";
|
|
6
|
+
const envPrefix = "DONATION_ALERTS";
|
|
7
|
+
const defaultScopes = ["oauth-user-show"];
|
|
8
|
+
export class DonationAlerts {
|
|
9
|
+
clientId;
|
|
10
|
+
clientSecret;
|
|
11
|
+
redirectURI;
|
|
12
|
+
auth = null;
|
|
13
|
+
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
14
|
+
if (typeof clientIdOrOptions === "object") {
|
|
15
|
+
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
|
|
16
|
+
clientSecret: true,
|
|
17
|
+
redirectURI: true
|
|
18
|
+
});
|
|
19
|
+
this.clientId = this.auth.clientId;
|
|
20
|
+
this.clientSecret = this.auth.clientSecret ?? "";
|
|
21
|
+
this.redirectURI = this.auth.redirectURI ?? "";
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this.clientId = clientIdOrOptions;
|
|
25
|
+
this.clientSecret = clientSecret ?? "";
|
|
26
|
+
this.redirectURI = redirectURI ?? "";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
createAuthorizationURL(scopes) {
|
|
30
|
+
const url = new URL(authorizationEndpoint);
|
|
31
|
+
url.searchParams.set("response_type", "code");
|
|
32
|
+
url.searchParams.set("client_id", this.clientId);
|
|
33
|
+
url.searchParams.set("scope", scopes.join(" "));
|
|
34
|
+
url.searchParams.set("redirect_uri", this.redirectURI);
|
|
35
|
+
return url;
|
|
36
|
+
}
|
|
37
|
+
async validateAuthorizationCode(code) {
|
|
38
|
+
const body = new URLSearchParams();
|
|
39
|
+
body.set("grant_type", "authorization_code");
|
|
40
|
+
body.set("code", code);
|
|
41
|
+
body.set("redirect_uri", this.redirectURI);
|
|
42
|
+
body.set("client_id", this.clientId);
|
|
43
|
+
body.set("client_secret", this.clientSecret);
|
|
44
|
+
const request = createOAuth2Request(tokenEndpoint, body);
|
|
45
|
+
const tokens = await sendTokenRequest(request);
|
|
46
|
+
return tokens;
|
|
47
|
+
}
|
|
48
|
+
async refreshAccessToken(refreshToken, scopes) {
|
|
49
|
+
const body = new URLSearchParams();
|
|
50
|
+
body.set("grant_type", "refresh_token");
|
|
51
|
+
body.set("refresh_token", refreshToken);
|
|
52
|
+
body.set("client_id", this.clientId);
|
|
53
|
+
body.set("client_secret", this.clientSecret);
|
|
54
|
+
body.set("scope", scopes.join(" "));
|
|
55
|
+
const request = createOAuth2Request(tokenEndpoint, body);
|
|
56
|
+
const tokens = await sendTokenRequest(request);
|
|
57
|
+
return tokens;
|
|
58
|
+
}
|
|
59
|
+
async getAuthorizationURL(scopes) {
|
|
60
|
+
const auth = requireAuthConfig(this.auth);
|
|
61
|
+
const state = generateOAuthState();
|
|
62
|
+
const url = this.createAuthorizationURL(resolveScopes(scopes, auth, defaultScopes));
|
|
63
|
+
// The legacy URL builder does not take a state parameter.
|
|
64
|
+
url.searchParams.set("state", state);
|
|
65
|
+
await saveOAuthState(auth.store, state, {});
|
|
66
|
+
return url;
|
|
67
|
+
}
|
|
68
|
+
async getUser(query) {
|
|
69
|
+
const auth = requireAuthConfig(this.auth);
|
|
70
|
+
const { code, state } = parseCallbackQuery(query);
|
|
71
|
+
await consumeOAuthState(auth.store, state);
|
|
72
|
+
const tokens = await this.validateAuthorizationCode(code);
|
|
73
|
+
const body = await fetchUserProfile(userEndpoint, tokens.accessToken());
|
|
74
|
+
const profile = body.data;
|
|
75
|
+
if (typeof profile !== "object" || profile === null) {
|
|
76
|
+
throw new OAuthProviderError("Unexpected user profile response body");
|
|
77
|
+
}
|
|
78
|
+
const user = profile;
|
|
79
|
+
return {
|
|
80
|
+
id: profileId(user.id),
|
|
81
|
+
name: profileString(user.name) ?? profileString(user.code),
|
|
82
|
+
email: profileString(user.email),
|
|
83
|
+
image: profileString(user.avatar)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OAuth2Tokens } from "../oauth2.js";
|
|
2
|
+
import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
|
|
3
|
+
export interface DribbbleOptions extends ProviderOptions {
|
|
4
|
+
}
|
|
5
|
+
export declare class Dribbble {
|
|
6
|
+
private clientId;
|
|
7
|
+
private clientSecret;
|
|
8
|
+
private redirectURI;
|
|
9
|
+
private auth;
|
|
10
|
+
constructor(options: DribbbleOptions);
|
|
11
|
+
constructor(clientId: string, clientSecret: string, redirectURI: string);
|
|
12
|
+
createAuthorizationURL(state: string, scopes: string[]): URL;
|
|
13
|
+
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
14
|
+
getAuthorizationURL(scopes?: string[]): Promise<URL>;
|
|
15
|
+
getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createOAuth2Request, sendTokenRequest } from "../request.js";
|
|
2
|
+
import { consumeOAuthState, fetchUserProfile, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
|
|
3
|
+
const authorizationEndpoint = "https://dribbble.com/oauth/authorize";
|
|
4
|
+
const tokenEndpoint = "https://dribbble.com/oauth/token";
|
|
5
|
+
const userEndpoint = "https://api.dribbble.com/v2/user";
|
|
6
|
+
const envPrefix = "DRIBBBLE";
|
|
7
|
+
// Dribbble grants the "public" scope by default.
|
|
8
|
+
const defaultScopes = [];
|
|
9
|
+
export class Dribbble {
|
|
10
|
+
clientId;
|
|
11
|
+
clientSecret;
|
|
12
|
+
redirectURI;
|
|
13
|
+
auth = null;
|
|
14
|
+
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
15
|
+
if (typeof clientIdOrOptions === "object") {
|
|
16
|
+
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
|
|
17
|
+
clientSecret: true,
|
|
18
|
+
redirectURI: true
|
|
19
|
+
});
|
|
20
|
+
this.clientId = this.auth.clientId;
|
|
21
|
+
this.clientSecret = this.auth.clientSecret ?? "";
|
|
22
|
+
this.redirectURI = this.auth.redirectURI ?? "";
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.clientId = clientIdOrOptions;
|
|
26
|
+
this.clientSecret = clientSecret ?? "";
|
|
27
|
+
this.redirectURI = redirectURI ?? "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
createAuthorizationURL(state, scopes) {
|
|
31
|
+
const url = new URL(authorizationEndpoint);
|
|
32
|
+
url.searchParams.set("response_type", "code");
|
|
33
|
+
url.searchParams.set("client_id", this.clientId);
|
|
34
|
+
url.searchParams.set("state", state);
|
|
35
|
+
if (scopes.length > 0) {
|
|
36
|
+
url.searchParams.set("scope", scopes.join(" "));
|
|
37
|
+
}
|
|
38
|
+
url.searchParams.set("redirect_uri", this.redirectURI);
|
|
39
|
+
return url;
|
|
40
|
+
}
|
|
41
|
+
async validateAuthorizationCode(code) {
|
|
42
|
+
const body = new URLSearchParams();
|
|
43
|
+
body.set("grant_type", "authorization_code");
|
|
44
|
+
body.set("code", code);
|
|
45
|
+
body.set("redirect_uri", this.redirectURI);
|
|
46
|
+
body.set("client_id", this.clientId);
|
|
47
|
+
body.set("client_secret", this.clientSecret);
|
|
48
|
+
const request = createOAuth2Request(tokenEndpoint, body);
|
|
49
|
+
const tokens = await sendTokenRequest(request);
|
|
50
|
+
return tokens;
|
|
51
|
+
}
|
|
52
|
+
async getAuthorizationURL(scopes) {
|
|
53
|
+
const auth = requireAuthConfig(this.auth);
|
|
54
|
+
const state = generateOAuthState();
|
|
55
|
+
const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
|
|
56
|
+
await saveOAuthState(auth.store, state, {});
|
|
57
|
+
return url;
|
|
58
|
+
}
|
|
59
|
+
async getUser(query) {
|
|
60
|
+
const auth = requireAuthConfig(this.auth);
|
|
61
|
+
const { code, state } = parseCallbackQuery(query);
|
|
62
|
+
await consumeOAuthState(auth.store, state);
|
|
63
|
+
const tokens = await this.validateAuthorizationCode(code);
|
|
64
|
+
const profile = await fetchUserProfile(userEndpoint, tokens.accessToken());
|
|
65
|
+
return {
|
|
66
|
+
id: profileId(profile.id),
|
|
67
|
+
name: profileString(profile.name) ?? profileString(profile.login),
|
|
68
|
+
// The v2 user endpoint does not expose an email address.
|
|
69
|
+
email: null,
|
|
70
|
+
image: profileString(profile.avatar_url)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OAuth2Tokens } from "../oauth2.js";
|
|
2
|
+
import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
|
|
3
|
+
export interface DropboxOptions extends ProviderOptions {
|
|
4
|
+
}
|
|
5
|
+
export declare class Dropbox {
|
|
6
|
+
private client;
|
|
7
|
+
private auth;
|
|
8
|
+
constructor(options: DropboxOptions);
|
|
9
|
+
constructor(clientId: string, clientSecret: string, redirectURI: string);
|
|
10
|
+
createAuthorizationURL(state: string, scopes: string[]): URL;
|
|
11
|
+
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
12
|
+
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
|
|
13
|
+
revokeToken(token: string): Promise<void>;
|
|
14
|
+
getAuthorizationURL(scopes?: string[]): Promise<URL>;
|
|
15
|
+
getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { OAuth2Client } from "../client.js";
|
|
2
|
+
import { consumeOAuthState, generateOAuthState, OAuthProviderError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
|
|
3
|
+
const authorizationEndpoint = "https://www.dropbox.com/oauth2/authorize";
|
|
4
|
+
const tokenEndpoint = "https://api.dropboxapi.com/oauth2/token";
|
|
5
|
+
const tokenRevocationEndpoint = "https://api.dropboxapi.com/2/auth/token/revoke";
|
|
6
|
+
const userEndpoint = "https://api.dropboxapi.com/2/users/get_current_account";
|
|
7
|
+
const envPrefix = "DROPBOX";
|
|
8
|
+
const defaultScopes = ["account_info.read"];
|
|
9
|
+
export class Dropbox {
|
|
10
|
+
client;
|
|
11
|
+
auth = null;
|
|
12
|
+
constructor(clientIdOrOptions, clientSecret, redirectURI) {
|
|
13
|
+
if (typeof clientIdOrOptions === "object") {
|
|
14
|
+
this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
|
|
15
|
+
clientSecret: true,
|
|
16
|
+
redirectURI: true
|
|
17
|
+
});
|
|
18
|
+
this.client = new OAuth2Client(this.auth.clientId, this.auth.clientSecret, this.auth.redirectURI);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
this.client = new OAuth2Client(clientIdOrOptions, clientSecret ?? null, redirectURI ?? null);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
createAuthorizationURL(state, scopes) {
|
|
25
|
+
const url = this.client.createAuthorizationURL(authorizationEndpoint, state, scopes);
|
|
26
|
+
return url;
|
|
27
|
+
}
|
|
28
|
+
async validateAuthorizationCode(code) {
|
|
29
|
+
const tokens = await this.client.validateAuthorizationCode(tokenEndpoint, code, null);
|
|
30
|
+
return tokens;
|
|
31
|
+
}
|
|
32
|
+
async refreshAccessToken(refreshToken) {
|
|
33
|
+
const tokens = await this.client.refreshAccessToken(tokenEndpoint, refreshToken, []);
|
|
34
|
+
return tokens;
|
|
35
|
+
}
|
|
36
|
+
async revokeToken(token) {
|
|
37
|
+
await this.client.revokeToken(tokenRevocationEndpoint, token);
|
|
38
|
+
}
|
|
39
|
+
async getAuthorizationURL(scopes) {
|
|
40
|
+
const auth = requireAuthConfig(this.auth);
|
|
41
|
+
const state = generateOAuthState();
|
|
42
|
+
const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
|
|
43
|
+
await saveOAuthState(auth.store, state, {});
|
|
44
|
+
return url;
|
|
45
|
+
}
|
|
46
|
+
async getUser(query) {
|
|
47
|
+
const auth = requireAuthConfig(this.auth);
|
|
48
|
+
const { code, state } = parseCallbackQuery(query);
|
|
49
|
+
await consumeOAuthState(auth.store, state);
|
|
50
|
+
const tokens = await this.validateAuthorizationCode(code);
|
|
51
|
+
const profile = await fetchCurrentAccount(tokens.accessToken());
|
|
52
|
+
let name = null;
|
|
53
|
+
if (typeof profile.name === "object" && profile.name !== null) {
|
|
54
|
+
name = profileString(profile.name.display_name);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
id: profileId(profile.account_id),
|
|
58
|
+
name,
|
|
59
|
+
email: profileString(profile.email),
|
|
60
|
+
image: profileString(profile.profile_photo_url)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Dropbox requires a POST with no body for the current account endpoint.
|
|
65
|
+
async function fetchCurrentAccount(accessToken) {
|
|
66
|
+
let response;
|
|
67
|
+
try {
|
|
68
|
+
response = await fetch(userEndpoint, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: {
|
|
71
|
+
Authorization: `Bearer ${accessToken}`,
|
|
72
|
+
"User-Agent": "arctic"
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new OAuthProviderError("Failed to fetch user profile");
|
|
78
|
+
}
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
if (response.body !== null) {
|
|
81
|
+
await response.body.cancel();
|
|
82
|
+
}
|
|
83
|
+
throw new OAuthProviderError(`User profile request failed with status ${response.status}`);
|
|
84
|
+
}
|
|
85
|
+
let data;
|
|
86
|
+
try {
|
|
87
|
+
data = await response.json();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
throw new OAuthProviderError("User profile response was not valid JSON");
|
|
91
|
+
}
|
|
92
|
+
if (typeof data !== "object" || data === null) {
|
|
93
|
+
throw new OAuthProviderError("Unexpected user profile response body");
|
|
94
|
+
}
|
|
95
|
+
return data;
|
|
96
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OAuth2Tokens } from "../oauth2.js";
|
|
2
|
+
import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
|
|
3
|
+
export interface EpicGamesOptions extends ProviderOptions {
|
|
4
|
+
}
|
|
5
|
+
export declare class EpicGames {
|
|
6
|
+
private client;
|
|
7
|
+
private auth;
|
|
8
|
+
constructor(options: EpicGamesOptions);
|
|
9
|
+
constructor(clientId: string, clientSecret: string, redirectURI: string);
|
|
10
|
+
createAuthorizationURL(state: string, scopes: string[]): URL;
|
|
11
|
+
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
|
|
12
|
+
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
|
|
13
|
+
revokeToken(token: string): Promise<void>;
|
|
14
|
+
getAuthorizationURL(scopes?: string[]): Promise<URL>;
|
|
15
|
+
getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
|
|
16
|
+
}
|