kavachos 0.4.0 → 0.4.2
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/dist/auth/index.d.ts +583 -32
- package/dist/auth/index.js +1673 -272
- package/dist/auth/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1672 -271
- package/dist/index.js.map +1 -1
- package/dist/standards/index.d.ts +139 -0
- package/dist/standards/index.js +72 -0
- package/dist/standards/index.js.map +1 -0
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -6036,15 +6036,110 @@ function mergeScopes(defaults, extras) {
|
|
|
6036
6036
|
return [...merged];
|
|
6037
6037
|
}
|
|
6038
6038
|
|
|
6039
|
+
// src/auth/oauth/providers/atlassian.ts
|
|
6040
|
+
var AUTHORIZATION_URL2 = "https://auth.atlassian.com/authorize";
|
|
6041
|
+
var TOKEN_URL2 = "https://auth.atlassian.com/oauth/token";
|
|
6042
|
+
var USER_INFO_URL = "https://api.atlassian.com/me";
|
|
6043
|
+
var ATLASSIAN_AUDIENCE = "api.atlassian.com";
|
|
6044
|
+
var DEFAULT_ATLASSIAN_SCOPES = ["read:me"];
|
|
6045
|
+
function normalizeProfile(raw) {
|
|
6046
|
+
const data = raw;
|
|
6047
|
+
if (!data.account_id) {
|
|
6048
|
+
throw new Error("Atlassian user response missing required field: account_id");
|
|
6049
|
+
}
|
|
6050
|
+
return {
|
|
6051
|
+
id: data.account_id,
|
|
6052
|
+
email: data.email,
|
|
6053
|
+
name: data.name,
|
|
6054
|
+
avatar: data.picture,
|
|
6055
|
+
raw
|
|
6056
|
+
};
|
|
6057
|
+
}
|
|
6058
|
+
function createAtlassianProvider(config) {
|
|
6059
|
+
const scopes = mergeScopes2(DEFAULT_ATLASSIAN_SCOPES, config.scopes);
|
|
6060
|
+
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6061
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6062
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6063
|
+
const params = new URLSearchParams({
|
|
6064
|
+
client_id: config.clientId,
|
|
6065
|
+
redirect_uri: effectiveRedirectUri,
|
|
6066
|
+
response_type: "code",
|
|
6067
|
+
scope: scopes.join(" "),
|
|
6068
|
+
state,
|
|
6069
|
+
code_challenge: codeChallenge,
|
|
6070
|
+
code_challenge_method: "S256",
|
|
6071
|
+
// Required: instructs Atlassian which API audience to issue tokens for.
|
|
6072
|
+
audience: ATLASSIAN_AUDIENCE,
|
|
6073
|
+
prompt: "consent"
|
|
6074
|
+
});
|
|
6075
|
+
return `${AUTHORIZATION_URL2}?${params.toString()}`;
|
|
6076
|
+
}
|
|
6077
|
+
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6078
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6079
|
+
const response = await fetch(TOKEN_URL2, {
|
|
6080
|
+
method: "POST",
|
|
6081
|
+
headers: { "Content-Type": "application/json" },
|
|
6082
|
+
body: JSON.stringify({
|
|
6083
|
+
grant_type: "authorization_code",
|
|
6084
|
+
client_id: config.clientId,
|
|
6085
|
+
client_secret: config.clientSecret,
|
|
6086
|
+
code: code2,
|
|
6087
|
+
code_verifier: codeVerifier,
|
|
6088
|
+
redirect_uri: effectiveRedirectUri
|
|
6089
|
+
})
|
|
6090
|
+
});
|
|
6091
|
+
if (!response.ok) {
|
|
6092
|
+
const text3 = await response.text();
|
|
6093
|
+
throw new Error(`Atlassian token exchange failed (${response.status}): ${text3}`);
|
|
6094
|
+
}
|
|
6095
|
+
const raw = await response.json();
|
|
6096
|
+
const data = raw;
|
|
6097
|
+
return {
|
|
6098
|
+
accessToken: data.access_token,
|
|
6099
|
+
refreshToken: data.refresh_token,
|
|
6100
|
+
expiresIn: data.expires_in,
|
|
6101
|
+
tokenType: data.token_type ?? "Bearer",
|
|
6102
|
+
raw
|
|
6103
|
+
};
|
|
6104
|
+
}
|
|
6105
|
+
async function getUserInfo(accessToken) {
|
|
6106
|
+
const response = await fetch(USER_INFO_URL, {
|
|
6107
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6108
|
+
});
|
|
6109
|
+
if (!response.ok) {
|
|
6110
|
+
const text3 = await response.text();
|
|
6111
|
+
throw new Error(`Atlassian /me fetch failed (${response.status}): ${text3}`);
|
|
6112
|
+
}
|
|
6113
|
+
const raw = await response.json();
|
|
6114
|
+
return normalizeProfile(raw);
|
|
6115
|
+
}
|
|
6116
|
+
return {
|
|
6117
|
+
id: "atlassian",
|
|
6118
|
+
name: "Atlassian",
|
|
6119
|
+
authorizationUrl: AUTHORIZATION_URL2,
|
|
6120
|
+
tokenUrl: TOKEN_URL2,
|
|
6121
|
+
userInfoUrl: USER_INFO_URL,
|
|
6122
|
+
scopes,
|
|
6123
|
+
getAuthorizationUrl,
|
|
6124
|
+
exchangeCode,
|
|
6125
|
+
getUserInfo
|
|
6126
|
+
};
|
|
6127
|
+
}
|
|
6128
|
+
function mergeScopes2(defaults, extras) {
|
|
6129
|
+
if (!extras || extras.length === 0) return defaults;
|
|
6130
|
+
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6131
|
+
return [...merged];
|
|
6132
|
+
}
|
|
6133
|
+
|
|
6039
6134
|
// src/auth/oauth/providers/discord.ts
|
|
6040
|
-
var
|
|
6041
|
-
var
|
|
6042
|
-
var
|
|
6135
|
+
var AUTHORIZATION_URL3 = "https://discord.com/api/oauth2/authorize";
|
|
6136
|
+
var TOKEN_URL3 = "https://discord.com/api/oauth2/token";
|
|
6137
|
+
var USER_INFO_URL2 = "https://discord.com/api/users/@me";
|
|
6043
6138
|
var CDN_BASE = "https://cdn.discordapp.com";
|
|
6044
6139
|
var DEFAULT_DISCORD_SCOPES = ["identify", "email"];
|
|
6045
6140
|
var DEFAULT_SCOPES2 = DEFAULT_DISCORD_SCOPES;
|
|
6046
6141
|
function createDiscordProvider(config) {
|
|
6047
|
-
const scopes =
|
|
6142
|
+
const scopes = mergeScopes3(DEFAULT_SCOPES2, config.scopes);
|
|
6048
6143
|
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6049
6144
|
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6050
6145
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6057,7 +6152,7 @@ function createDiscordProvider(config) {
|
|
|
6057
6152
|
code_challenge: codeChallenge,
|
|
6058
6153
|
code_challenge_method: "S256"
|
|
6059
6154
|
});
|
|
6060
|
-
return `${
|
|
6155
|
+
return `${AUTHORIZATION_URL3}?${params.toString()}`;
|
|
6061
6156
|
}
|
|
6062
6157
|
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6063
6158
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6069,7 +6164,7 @@ function createDiscordProvider(config) {
|
|
|
6069
6164
|
code_verifier: codeVerifier,
|
|
6070
6165
|
redirect_uri: effectiveRedirectUri
|
|
6071
6166
|
});
|
|
6072
|
-
const response = await fetch(
|
|
6167
|
+
const response = await fetch(TOKEN_URL3, {
|
|
6073
6168
|
method: "POST",
|
|
6074
6169
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6075
6170
|
body: body.toString()
|
|
@@ -6089,7 +6184,7 @@ function createDiscordProvider(config) {
|
|
|
6089
6184
|
};
|
|
6090
6185
|
}
|
|
6091
6186
|
async function getUserInfo(accessToken) {
|
|
6092
|
-
const response = await fetch(
|
|
6187
|
+
const response = await fetch(USER_INFO_URL2, {
|
|
6093
6188
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6094
6189
|
});
|
|
6095
6190
|
if (!response.ok) {
|
|
@@ -6117,15 +6212,33 @@ function createDiscordProvider(config) {
|
|
|
6117
6212
|
return {
|
|
6118
6213
|
id: "discord",
|
|
6119
6214
|
name: "Discord",
|
|
6120
|
-
authorizationUrl:
|
|
6121
|
-
tokenUrl:
|
|
6122
|
-
userInfoUrl:
|
|
6215
|
+
authorizationUrl: AUTHORIZATION_URL3,
|
|
6216
|
+
tokenUrl: TOKEN_URL3,
|
|
6217
|
+
userInfoUrl: USER_INFO_URL2,
|
|
6123
6218
|
scopes,
|
|
6124
6219
|
getAuthorizationUrl,
|
|
6125
6220
|
exchangeCode,
|
|
6126
6221
|
getUserInfo
|
|
6127
6222
|
};
|
|
6128
6223
|
}
|
|
6224
|
+
function normalizeProfile2(raw) {
|
|
6225
|
+
const data = raw;
|
|
6226
|
+
if (!data.id) {
|
|
6227
|
+
throw new Error("Discord user response missing required field: id");
|
|
6228
|
+
}
|
|
6229
|
+
if (!data.email) {
|
|
6230
|
+
throw new Error("Discord user response has no email. Ensure the `email` scope is granted.");
|
|
6231
|
+
}
|
|
6232
|
+
const avatar = buildAvatarUrl(data.id, data.avatar);
|
|
6233
|
+
const name = data.global_name ?? buildLegacyName(data.username, data.discriminator);
|
|
6234
|
+
return {
|
|
6235
|
+
id: data.id,
|
|
6236
|
+
email: data.email,
|
|
6237
|
+
name,
|
|
6238
|
+
avatar,
|
|
6239
|
+
raw
|
|
6240
|
+
};
|
|
6241
|
+
}
|
|
6129
6242
|
function buildAvatarUrl(userId, avatarHash) {
|
|
6130
6243
|
if (!avatarHash) return void 0;
|
|
6131
6244
|
const ext = avatarHash.startsWith("a_") ? "gif" : "png";
|
|
@@ -6137,135 +6250,138 @@ function buildLegacyName(username, discriminator) {
|
|
|
6137
6250
|
}
|
|
6138
6251
|
return username;
|
|
6139
6252
|
}
|
|
6140
|
-
function
|
|
6253
|
+
function mergeScopes3(defaults, extras) {
|
|
6141
6254
|
if (!extras || extras.length === 0) return defaults;
|
|
6142
6255
|
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6143
6256
|
return [...merged];
|
|
6144
6257
|
}
|
|
6145
6258
|
|
|
6146
|
-
// src/auth/oauth/providers/
|
|
6147
|
-
var
|
|
6148
|
-
var
|
|
6149
|
-
var
|
|
6150
|
-
var
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6259
|
+
// src/auth/oauth/providers/dropbox.ts
|
|
6260
|
+
var AUTHORIZATION_URL4 = "https://www.dropbox.com/oauth2/authorize";
|
|
6261
|
+
var TOKEN_URL4 = "https://api.dropboxapi.com/oauth2/token";
|
|
6262
|
+
var USER_INFO_URL3 = "https://api.dropboxapi.com/2/users/get_current_account";
|
|
6263
|
+
var DEFAULT_DROPBOX_SCOPES = ["account_info.read"];
|
|
6264
|
+
function normalizeProfile3(raw) {
|
|
6265
|
+
const data = raw;
|
|
6266
|
+
if (!data.account_id) {
|
|
6267
|
+
throw new Error("Dropbox user response missing required field: account_id");
|
|
6268
|
+
}
|
|
6269
|
+
if (!data.email) {
|
|
6270
|
+
throw new Error("Dropbox user response missing required field: email");
|
|
6271
|
+
}
|
|
6272
|
+
return {
|
|
6273
|
+
id: data.account_id,
|
|
6274
|
+
email: data.email,
|
|
6275
|
+
name: data.name?.display_name,
|
|
6276
|
+
avatar: data.profile_photo_url ?? data.profile_photo?.url,
|
|
6277
|
+
raw
|
|
6278
|
+
};
|
|
6279
|
+
}
|
|
6280
|
+
function createDropboxProvider(config) {
|
|
6281
|
+
const scopes = mergeScopes4(DEFAULT_DROPBOX_SCOPES, config.scopes);
|
|
6154
6282
|
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6155
6283
|
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6156
6284
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6157
6285
|
const params = new URLSearchParams({
|
|
6158
6286
|
client_id: config.clientId,
|
|
6159
6287
|
redirect_uri: effectiveRedirectUri,
|
|
6288
|
+
response_type: "code",
|
|
6160
6289
|
scope: scopes.join(" "),
|
|
6161
6290
|
state,
|
|
6162
|
-
// Included for symmetry; GitHub ignores unknown parameters.
|
|
6163
6291
|
code_challenge: codeChallenge,
|
|
6164
|
-
code_challenge_method: "S256"
|
|
6292
|
+
code_challenge_method: "S256",
|
|
6293
|
+
token_access_type: "offline"
|
|
6165
6294
|
});
|
|
6166
|
-
return `${
|
|
6295
|
+
return `${AUTHORIZATION_URL4}?${params.toString()}`;
|
|
6167
6296
|
}
|
|
6168
6297
|
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6169
6298
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6170
6299
|
const body = new URLSearchParams({
|
|
6300
|
+
grant_type: "authorization_code",
|
|
6171
6301
|
client_id: config.clientId,
|
|
6172
6302
|
client_secret: config.clientSecret,
|
|
6173
6303
|
code: code2,
|
|
6174
|
-
|
|
6175
|
-
|
|
6304
|
+
code_verifier: codeVerifier,
|
|
6305
|
+
redirect_uri: effectiveRedirectUri
|
|
6176
6306
|
});
|
|
6177
|
-
const response = await fetch(
|
|
6307
|
+
const response = await fetch(TOKEN_URL4, {
|
|
6178
6308
|
method: "POST",
|
|
6179
|
-
headers: {
|
|
6180
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
6181
|
-
Accept: "application/json"
|
|
6182
|
-
},
|
|
6309
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6183
6310
|
body: body.toString()
|
|
6184
6311
|
});
|
|
6185
6312
|
if (!response.ok) {
|
|
6186
6313
|
const text3 = await response.text();
|
|
6187
|
-
throw new Error(`
|
|
6314
|
+
throw new Error(`Dropbox token exchange failed (${response.status}): ${text3}`);
|
|
6188
6315
|
}
|
|
6189
6316
|
const raw = await response.json();
|
|
6190
6317
|
const data = raw;
|
|
6191
|
-
if (data.error) {
|
|
6192
|
-
throw new Error(
|
|
6193
|
-
`GitHub token exchange error: ${data.error} \u2014 ${data.error_description ?? ""}`
|
|
6194
|
-
);
|
|
6195
|
-
}
|
|
6196
|
-
if (!data.access_token) {
|
|
6197
|
-
throw new Error("GitHub token exchange returned no access_token");
|
|
6198
|
-
}
|
|
6199
6318
|
return {
|
|
6200
6319
|
accessToken: data.access_token,
|
|
6201
6320
|
refreshToken: data.refresh_token,
|
|
6202
6321
|
expiresIn: data.expires_in,
|
|
6203
|
-
tokenType: data.token_type ?? "
|
|
6322
|
+
tokenType: data.token_type ?? "Bearer",
|
|
6204
6323
|
raw
|
|
6205
6324
|
};
|
|
6206
6325
|
}
|
|
6207
6326
|
async function getUserInfo(accessToken) {
|
|
6208
|
-
const
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
const raw = await profileResponse.json();
|
|
6219
|
-
const profile = raw;
|
|
6220
|
-
let email = typeof profile.email === "string" ? profile.email : null;
|
|
6221
|
-
if (!email) {
|
|
6222
|
-
email = await fetchPrimaryEmail(accessToken, headers);
|
|
6223
|
-
}
|
|
6224
|
-
if (!email) {
|
|
6327
|
+
const response = await fetch(USER_INFO_URL3, {
|
|
6328
|
+
method: "POST",
|
|
6329
|
+
headers: {
|
|
6330
|
+
Authorization: `Bearer ${accessToken}`,
|
|
6331
|
+
"Content-Type": "application/json"
|
|
6332
|
+
},
|
|
6333
|
+
body: "null"
|
|
6334
|
+
});
|
|
6335
|
+
if (!response.ok) {
|
|
6336
|
+
const text3 = await response.text();
|
|
6225
6337
|
throw new Error(
|
|
6226
|
-
|
|
6338
|
+
`Dropbox /2/users/get_current_account fetch failed (${response.status}): ${text3}`
|
|
6227
6339
|
);
|
|
6228
6340
|
}
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
email,
|
|
6232
|
-
name: profile.name ?? profile.login,
|
|
6233
|
-
avatar: profile.avatar_url,
|
|
6234
|
-
raw
|
|
6235
|
-
};
|
|
6341
|
+
const raw = await response.json();
|
|
6342
|
+
return normalizeProfile3(raw);
|
|
6236
6343
|
}
|
|
6237
6344
|
return {
|
|
6238
|
-
id: "
|
|
6239
|
-
name: "
|
|
6240
|
-
authorizationUrl:
|
|
6241
|
-
tokenUrl:
|
|
6242
|
-
userInfoUrl:
|
|
6345
|
+
id: "dropbox",
|
|
6346
|
+
name: "Dropbox",
|
|
6347
|
+
authorizationUrl: AUTHORIZATION_URL4,
|
|
6348
|
+
tokenUrl: TOKEN_URL4,
|
|
6349
|
+
userInfoUrl: USER_INFO_URL3,
|
|
6243
6350
|
scopes,
|
|
6244
6351
|
getAuthorizationUrl,
|
|
6245
6352
|
exchangeCode,
|
|
6246
6353
|
getUserInfo
|
|
6247
6354
|
};
|
|
6248
6355
|
}
|
|
6249
|
-
|
|
6250
|
-
const response = await fetch(USER_EMAILS_URL, { headers });
|
|
6251
|
-
if (!response.ok) return null;
|
|
6252
|
-
const emails = await response.json();
|
|
6253
|
-
const primary = emails.find((e) => e.primary && e.verified);
|
|
6254
|
-
return primary?.email ?? null;
|
|
6255
|
-
}
|
|
6256
|
-
function mergeScopes3(defaults, extras) {
|
|
6356
|
+
function mergeScopes4(defaults, extras) {
|
|
6257
6357
|
if (!extras || extras.length === 0) return defaults;
|
|
6258
6358
|
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6259
6359
|
return [...merged];
|
|
6260
6360
|
}
|
|
6261
6361
|
|
|
6262
|
-
// src/auth/oauth/providers/
|
|
6263
|
-
var
|
|
6264
|
-
var
|
|
6265
|
-
var
|
|
6266
|
-
var
|
|
6267
|
-
function
|
|
6268
|
-
const
|
|
6362
|
+
// src/auth/oauth/providers/figma.ts
|
|
6363
|
+
var AUTHORIZATION_URL5 = "https://www.figma.com/oauth";
|
|
6364
|
+
var TOKEN_URL5 = "https://api.figma.com/v1/oauth/token";
|
|
6365
|
+
var USER_INFO_URL4 = "https://api.figma.com/v1/me";
|
|
6366
|
+
var DEFAULT_FIGMA_SCOPES = ["file_read"];
|
|
6367
|
+
function normalizeProfile4(raw) {
|
|
6368
|
+
const data = raw;
|
|
6369
|
+
if (!data.id) {
|
|
6370
|
+
throw new Error("Figma user response missing required field: id");
|
|
6371
|
+
}
|
|
6372
|
+
if (!data.email) {
|
|
6373
|
+
throw new Error("Figma user response missing required field: email");
|
|
6374
|
+
}
|
|
6375
|
+
return {
|
|
6376
|
+
id: data.id,
|
|
6377
|
+
email: data.email,
|
|
6378
|
+
name: data.handle,
|
|
6379
|
+
avatar: data.img_url,
|
|
6380
|
+
raw
|
|
6381
|
+
};
|
|
6382
|
+
}
|
|
6383
|
+
function createFigmaProvider(config) {
|
|
6384
|
+
const scopes = mergeScopes5(DEFAULT_FIGMA_SCOPES, config.scopes);
|
|
6269
6385
|
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6270
6386
|
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6271
6387
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6278,26 +6394,26 @@ function createGitlabProvider(config) {
|
|
|
6278
6394
|
code_challenge: codeChallenge,
|
|
6279
6395
|
code_challenge_method: "S256"
|
|
6280
6396
|
});
|
|
6281
|
-
return `${
|
|
6397
|
+
return `${AUTHORIZATION_URL5}?${params.toString()}`;
|
|
6282
6398
|
}
|
|
6283
6399
|
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6284
6400
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6285
6401
|
const body = new URLSearchParams({
|
|
6286
|
-
grant_type: "authorization_code",
|
|
6287
6402
|
client_id: config.clientId,
|
|
6288
6403
|
client_secret: config.clientSecret,
|
|
6404
|
+
redirect_uri: effectiveRedirectUri,
|
|
6289
6405
|
code: code2,
|
|
6290
6406
|
code_verifier: codeVerifier,
|
|
6291
|
-
|
|
6407
|
+
grant_type: "authorization_code"
|
|
6292
6408
|
});
|
|
6293
|
-
const response = await fetch(
|
|
6409
|
+
const response = await fetch(TOKEN_URL5, {
|
|
6294
6410
|
method: "POST",
|
|
6295
6411
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6296
6412
|
body: body.toString()
|
|
6297
6413
|
});
|
|
6298
6414
|
if (!response.ok) {
|
|
6299
6415
|
const text3 = await response.text();
|
|
6300
|
-
throw new Error(`
|
|
6416
|
+
throw new Error(`Figma token exchange failed (${response.status}): ${text3}`);
|
|
6301
6417
|
}
|
|
6302
6418
|
const raw = await response.json();
|
|
6303
6419
|
const data = raw;
|
|
@@ -6310,58 +6426,84 @@ function createGitlabProvider(config) {
|
|
|
6310
6426
|
};
|
|
6311
6427
|
}
|
|
6312
6428
|
async function getUserInfo(accessToken) {
|
|
6313
|
-
const response = await fetch(
|
|
6429
|
+
const response = await fetch(USER_INFO_URL4, {
|
|
6314
6430
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6315
6431
|
});
|
|
6316
6432
|
if (!response.ok) {
|
|
6317
6433
|
const text3 = await response.text();
|
|
6318
|
-
throw new Error(`
|
|
6434
|
+
throw new Error(`Figma /v1/me fetch failed (${response.status}): ${text3}`);
|
|
6319
6435
|
}
|
|
6320
6436
|
const raw = await response.json();
|
|
6321
|
-
|
|
6322
|
-
if (!data.id) {
|
|
6323
|
-
throw new Error("GitLab user response missing required field: id");
|
|
6324
|
-
}
|
|
6325
|
-
const email = data.email ?? data.public_email;
|
|
6326
|
-
if (!email) {
|
|
6327
|
-
throw new Error(
|
|
6328
|
-
"GitLab user response has no email. The account may have restricted email visibility."
|
|
6329
|
-
);
|
|
6330
|
-
}
|
|
6331
|
-
return {
|
|
6332
|
-
id: String(data.id),
|
|
6333
|
-
email,
|
|
6334
|
-
name: data.name ?? data.username,
|
|
6335
|
-
avatar: data.avatar_url,
|
|
6336
|
-
raw
|
|
6337
|
-
};
|
|
6437
|
+
return normalizeProfile4(raw);
|
|
6338
6438
|
}
|
|
6339
6439
|
return {
|
|
6340
|
-
id: "
|
|
6341
|
-
name: "
|
|
6342
|
-
authorizationUrl:
|
|
6343
|
-
tokenUrl:
|
|
6344
|
-
userInfoUrl:
|
|
6440
|
+
id: "figma",
|
|
6441
|
+
name: "Figma",
|
|
6442
|
+
authorizationUrl: AUTHORIZATION_URL5,
|
|
6443
|
+
tokenUrl: TOKEN_URL5,
|
|
6444
|
+
userInfoUrl: USER_INFO_URL4,
|
|
6345
6445
|
scopes,
|
|
6346
6446
|
getAuthorizationUrl,
|
|
6347
6447
|
exchangeCode,
|
|
6348
6448
|
getUserInfo
|
|
6349
6449
|
};
|
|
6350
6450
|
}
|
|
6351
|
-
function
|
|
6451
|
+
function mergeScopes5(defaults, extras) {
|
|
6352
6452
|
if (!extras || extras.length === 0) return defaults;
|
|
6353
6453
|
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6354
6454
|
return [...merged];
|
|
6355
6455
|
}
|
|
6356
6456
|
|
|
6357
|
-
// src/auth/oauth/providers/
|
|
6358
|
-
var
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
const
|
|
6457
|
+
// src/auth/oauth/providers/generic.ts
|
|
6458
|
+
var discoveryCache = /* @__PURE__ */ new Map();
|
|
6459
|
+
async function discoverEndpoints(issuer) {
|
|
6460
|
+
const cached = discoveryCache.get(issuer);
|
|
6461
|
+
if (cached) return cached;
|
|
6462
|
+
const url = `${issuer.replace(/\/$/, "")}/.well-known/openid-configuration`;
|
|
6463
|
+
const response = await fetch(url);
|
|
6464
|
+
if (!response.ok) {
|
|
6465
|
+
throw new Error(
|
|
6466
|
+
`OIDC discovery failed for issuer "${issuer}" (${response.status}). Provide explicit authorizationUrl / tokenUrl / userinfoUrl to skip discovery.`
|
|
6467
|
+
);
|
|
6468
|
+
}
|
|
6469
|
+
const doc = await response.json();
|
|
6470
|
+
const authorizationUrl = assertString(
|
|
6471
|
+
doc.authorization_endpoint,
|
|
6472
|
+
"authorization_endpoint",
|
|
6473
|
+
issuer
|
|
6474
|
+
);
|
|
6475
|
+
const tokenUrl = assertString(doc.token_endpoint, "token_endpoint", issuer);
|
|
6476
|
+
const userinfoUrl = assertString(doc.userinfo_endpoint, "userinfo_endpoint", issuer);
|
|
6477
|
+
const endpoints = { authorizationUrl, tokenUrl, userinfoUrl };
|
|
6478
|
+
discoveryCache.set(issuer, endpoints);
|
|
6479
|
+
return endpoints;
|
|
6480
|
+
}
|
|
6481
|
+
function assertString(value, field, issuer) {
|
|
6482
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
6483
|
+
throw new Error(`OIDC discovery for "${issuer}" returned no "${field}" field.`);
|
|
6484
|
+
}
|
|
6485
|
+
return value;
|
|
6486
|
+
}
|
|
6487
|
+
function genericOIDC(config) {
|
|
6488
|
+
const defaultScopes = ["openid", "email", "profile"];
|
|
6489
|
+
const scopes = mergeScopes6(defaultScopes, config.scopes);
|
|
6490
|
+
async function resolveEndpoints() {
|
|
6491
|
+
if (config.authorizationUrl && config.tokenUrl && config.userinfoUrl) {
|
|
6492
|
+
return {
|
|
6493
|
+
authorizationUrl: config.authorizationUrl,
|
|
6494
|
+
tokenUrl: config.tokenUrl,
|
|
6495
|
+
userinfoUrl: config.userinfoUrl
|
|
6496
|
+
};
|
|
6497
|
+
}
|
|
6498
|
+
const discovered = await discoverEndpoints(config.issuer);
|
|
6499
|
+
return {
|
|
6500
|
+
authorizationUrl: config.authorizationUrl ?? discovered.authorizationUrl,
|
|
6501
|
+
tokenUrl: config.tokenUrl ?? discovered.tokenUrl,
|
|
6502
|
+
userinfoUrl: config.userinfoUrl ?? discovered.userinfoUrl
|
|
6503
|
+
};
|
|
6504
|
+
}
|
|
6364
6505
|
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6506
|
+
const endpoints = await resolveEndpoints();
|
|
6365
6507
|
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6366
6508
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6367
6509
|
const params = new URLSearchParams({
|
|
@@ -6371,15 +6513,12 @@ function createGoogleProvider(config) {
|
|
|
6371
6513
|
scope: scopes.join(" "),
|
|
6372
6514
|
state,
|
|
6373
6515
|
code_challenge: codeChallenge,
|
|
6374
|
-
code_challenge_method: "S256"
|
|
6375
|
-
access_type: "offline",
|
|
6376
|
-
// request refresh token
|
|
6377
|
-
prompt: "consent"
|
|
6378
|
-
// always show consent to get refresh token reliably
|
|
6516
|
+
code_challenge_method: "S256"
|
|
6379
6517
|
});
|
|
6380
|
-
return `${
|
|
6518
|
+
return `${endpoints.authorizationUrl}?${params.toString()}`;
|
|
6381
6519
|
}
|
|
6382
6520
|
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6521
|
+
const endpoints = await resolveEndpoints();
|
|
6383
6522
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6384
6523
|
const body = new URLSearchParams({
|
|
6385
6524
|
grant_type: "authorization_code",
|
|
@@ -6389,14 +6528,14 @@ function createGoogleProvider(config) {
|
|
|
6389
6528
|
code_verifier: codeVerifier,
|
|
6390
6529
|
redirect_uri: effectiveRedirectUri
|
|
6391
6530
|
});
|
|
6392
|
-
const response = await fetch(
|
|
6531
|
+
const response = await fetch(endpoints.tokenUrl, {
|
|
6393
6532
|
method: "POST",
|
|
6394
6533
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6395
6534
|
body: body.toString()
|
|
6396
6535
|
});
|
|
6397
6536
|
if (!response.ok) {
|
|
6398
6537
|
const text3 = await response.text();
|
|
6399
|
-
throw new Error(
|
|
6538
|
+
throw new Error(`${config.name} token exchange failed (${response.status}): ${text3}`);
|
|
6400
6539
|
}
|
|
6401
6540
|
const raw = await response.json();
|
|
6402
6541
|
const data = raw;
|
|
@@ -6409,64 +6548,1190 @@ function createGoogleProvider(config) {
|
|
|
6409
6548
|
};
|
|
6410
6549
|
}
|
|
6411
6550
|
async function getUserInfo(accessToken) {
|
|
6412
|
-
const
|
|
6551
|
+
const endpoints = await resolveEndpoints();
|
|
6552
|
+
const response = await fetch(endpoints.userinfoUrl, {
|
|
6413
6553
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6414
6554
|
});
|
|
6415
6555
|
if (!response.ok) {
|
|
6416
6556
|
const text3 = await response.text();
|
|
6417
|
-
throw new Error(
|
|
6557
|
+
throw new Error(`${config.name} userinfo fetch failed (${response.status}): ${text3}`);
|
|
6558
|
+
}
|
|
6559
|
+
const raw = await response.json();
|
|
6560
|
+
const data = raw;
|
|
6561
|
+
if (!data.sub) {
|
|
6562
|
+
throw new Error(`${config.name} userinfo response missing required "sub" field.`);
|
|
6563
|
+
}
|
|
6564
|
+
const email = data.email ?? "";
|
|
6565
|
+
if (!email) {
|
|
6566
|
+
throw new Error(
|
|
6567
|
+
`${config.name} userinfo response missing "email". Ensure the 'email' scope is included.`
|
|
6568
|
+
);
|
|
6569
|
+
}
|
|
6570
|
+
return {
|
|
6571
|
+
id: data.sub,
|
|
6572
|
+
email,
|
|
6573
|
+
name: data.name,
|
|
6574
|
+
avatar: data.picture,
|
|
6575
|
+
raw
|
|
6576
|
+
};
|
|
6577
|
+
}
|
|
6578
|
+
const staticAuthUrl = config.authorizationUrl ?? `${config.issuer.replace(/\/$/, "")}/.well-known/openid-configuration`;
|
|
6579
|
+
return {
|
|
6580
|
+
id: config.id,
|
|
6581
|
+
name: config.name,
|
|
6582
|
+
authorizationUrl: staticAuthUrl,
|
|
6583
|
+
tokenUrl: config.tokenUrl ?? config.issuer,
|
|
6584
|
+
userInfoUrl: config.userinfoUrl ?? config.issuer,
|
|
6585
|
+
scopes,
|
|
6586
|
+
getAuthorizationUrl,
|
|
6587
|
+
exchangeCode,
|
|
6588
|
+
getUserInfo
|
|
6589
|
+
};
|
|
6590
|
+
}
|
|
6591
|
+
function mergeScopes6(defaults, extras) {
|
|
6592
|
+
if (!extras || extras.length === 0) return defaults;
|
|
6593
|
+
return [.../* @__PURE__ */ new Set([...defaults, ...extras])];
|
|
6594
|
+
}
|
|
6595
|
+
|
|
6596
|
+
// src/auth/oauth/providers/github.ts
|
|
6597
|
+
var AUTHORIZATION_URL6 = "https://github.com/login/oauth/authorize";
|
|
6598
|
+
var TOKEN_URL6 = "https://github.com/login/oauth/access_token";
|
|
6599
|
+
var USER_URL = "https://api.github.com/user";
|
|
6600
|
+
var USER_EMAILS_URL = "https://api.github.com/user/emails";
|
|
6601
|
+
var DEFAULT_SCOPES3 = ["user:email"];
|
|
6602
|
+
function createGithubProvider(config) {
|
|
6603
|
+
const scopes = mergeScopes7(DEFAULT_SCOPES3, config.scopes);
|
|
6604
|
+
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6605
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6606
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6607
|
+
const params = new URLSearchParams({
|
|
6608
|
+
client_id: config.clientId,
|
|
6609
|
+
redirect_uri: effectiveRedirectUri,
|
|
6610
|
+
scope: scopes.join(" "),
|
|
6611
|
+
state,
|
|
6612
|
+
// Included for symmetry; GitHub ignores unknown parameters.
|
|
6613
|
+
code_challenge: codeChallenge,
|
|
6614
|
+
code_challenge_method: "S256"
|
|
6615
|
+
});
|
|
6616
|
+
return `${AUTHORIZATION_URL6}?${params.toString()}`;
|
|
6617
|
+
}
|
|
6618
|
+
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6619
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6620
|
+
const body = new URLSearchParams({
|
|
6621
|
+
client_id: config.clientId,
|
|
6622
|
+
client_secret: config.clientSecret,
|
|
6623
|
+
code: code2,
|
|
6624
|
+
redirect_uri: effectiveRedirectUri,
|
|
6625
|
+
code_verifier: codeVerifier
|
|
6626
|
+
});
|
|
6627
|
+
const response = await fetch(TOKEN_URL6, {
|
|
6628
|
+
method: "POST",
|
|
6629
|
+
headers: {
|
|
6630
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
6631
|
+
Accept: "application/json"
|
|
6632
|
+
},
|
|
6633
|
+
body: body.toString()
|
|
6634
|
+
});
|
|
6635
|
+
if (!response.ok) {
|
|
6636
|
+
const text3 = await response.text();
|
|
6637
|
+
throw new Error(`GitHub token exchange failed (${response.status}): ${text3}`);
|
|
6638
|
+
}
|
|
6639
|
+
const raw = await response.json();
|
|
6640
|
+
const data = raw;
|
|
6641
|
+
if (data.error) {
|
|
6642
|
+
throw new Error(
|
|
6643
|
+
`GitHub token exchange error: ${data.error} \u2014 ${data.error_description ?? ""}`
|
|
6644
|
+
);
|
|
6645
|
+
}
|
|
6646
|
+
if (!data.access_token) {
|
|
6647
|
+
throw new Error("GitHub token exchange returned no access_token");
|
|
6648
|
+
}
|
|
6649
|
+
return {
|
|
6650
|
+
accessToken: data.access_token,
|
|
6651
|
+
refreshToken: data.refresh_token,
|
|
6652
|
+
expiresIn: data.expires_in,
|
|
6653
|
+
tokenType: data.token_type ?? "bearer",
|
|
6654
|
+
raw
|
|
6655
|
+
};
|
|
6656
|
+
}
|
|
6657
|
+
async function getUserInfo(accessToken) {
|
|
6658
|
+
const headers = {
|
|
6659
|
+
Authorization: `Bearer ${accessToken}`,
|
|
6660
|
+
Accept: "application/vnd.github+json",
|
|
6661
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
6662
|
+
};
|
|
6663
|
+
const profileResponse = await fetch(USER_URL, { headers });
|
|
6664
|
+
if (!profileResponse.ok) {
|
|
6665
|
+
const text3 = await profileResponse.text();
|
|
6666
|
+
throw new Error(`GitHub user fetch failed (${profileResponse.status}): ${text3}`);
|
|
6667
|
+
}
|
|
6668
|
+
const raw = await profileResponse.json();
|
|
6669
|
+
const profile = raw;
|
|
6670
|
+
let email = typeof profile.email === "string" ? profile.email : null;
|
|
6671
|
+
if (!email) {
|
|
6672
|
+
email = await fetchPrimaryEmail(accessToken, headers);
|
|
6673
|
+
}
|
|
6674
|
+
if (!email) {
|
|
6675
|
+
throw new Error(
|
|
6676
|
+
"GitHub user has no accessible email. Ensure the user:email scope is granted."
|
|
6677
|
+
);
|
|
6678
|
+
}
|
|
6679
|
+
return {
|
|
6680
|
+
id: String(profile.id),
|
|
6681
|
+
email,
|
|
6682
|
+
name: profile.name ?? profile.login,
|
|
6683
|
+
avatar: profile.avatar_url,
|
|
6684
|
+
raw
|
|
6685
|
+
};
|
|
6686
|
+
}
|
|
6687
|
+
return {
|
|
6688
|
+
id: "github",
|
|
6689
|
+
name: "GitHub",
|
|
6690
|
+
authorizationUrl: AUTHORIZATION_URL6,
|
|
6691
|
+
tokenUrl: TOKEN_URL6,
|
|
6692
|
+
userInfoUrl: USER_URL,
|
|
6693
|
+
scopes,
|
|
6694
|
+
getAuthorizationUrl,
|
|
6695
|
+
exchangeCode,
|
|
6696
|
+
getUserInfo
|
|
6697
|
+
};
|
|
6698
|
+
}
|
|
6699
|
+
async function fetchPrimaryEmail(_accessToken, headers) {
|
|
6700
|
+
const response = await fetch(USER_EMAILS_URL, { headers });
|
|
6701
|
+
if (!response.ok) return null;
|
|
6702
|
+
const emails = await response.json();
|
|
6703
|
+
const primary = emails.find((e) => e.primary && e.verified);
|
|
6704
|
+
return primary?.email ?? null;
|
|
6705
|
+
}
|
|
6706
|
+
function mergeScopes7(defaults, extras) {
|
|
6707
|
+
if (!extras || extras.length === 0) return defaults;
|
|
6708
|
+
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6709
|
+
return [...merged];
|
|
6710
|
+
}
|
|
6711
|
+
|
|
6712
|
+
// src/auth/oauth/providers/gitlab.ts
|
|
6713
|
+
var AUTHORIZATION_URL7 = "https://gitlab.com/oauth/authorize";
|
|
6714
|
+
var TOKEN_URL7 = "https://gitlab.com/oauth/token";
|
|
6715
|
+
var USER_INFO_URL5 = "https://gitlab.com/api/v4/user";
|
|
6716
|
+
var DEFAULT_SCOPES4 = ["read_user"];
|
|
6717
|
+
function createGitlabProvider(config) {
|
|
6718
|
+
const scopes = mergeScopes8(DEFAULT_SCOPES4, config.scopes);
|
|
6719
|
+
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6720
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6721
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6722
|
+
const params = new URLSearchParams({
|
|
6723
|
+
client_id: config.clientId,
|
|
6724
|
+
redirect_uri: effectiveRedirectUri,
|
|
6725
|
+
response_type: "code",
|
|
6726
|
+
scope: scopes.join(" "),
|
|
6727
|
+
state,
|
|
6728
|
+
code_challenge: codeChallenge,
|
|
6729
|
+
code_challenge_method: "S256"
|
|
6730
|
+
});
|
|
6731
|
+
return `${AUTHORIZATION_URL7}?${params.toString()}`;
|
|
6732
|
+
}
|
|
6733
|
+
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6734
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6735
|
+
const body = new URLSearchParams({
|
|
6736
|
+
grant_type: "authorization_code",
|
|
6737
|
+
client_id: config.clientId,
|
|
6738
|
+
client_secret: config.clientSecret,
|
|
6739
|
+
code: code2,
|
|
6740
|
+
code_verifier: codeVerifier,
|
|
6741
|
+
redirect_uri: effectiveRedirectUri
|
|
6742
|
+
});
|
|
6743
|
+
const response = await fetch(TOKEN_URL7, {
|
|
6744
|
+
method: "POST",
|
|
6745
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6746
|
+
body: body.toString()
|
|
6747
|
+
});
|
|
6748
|
+
if (!response.ok) {
|
|
6749
|
+
const text3 = await response.text();
|
|
6750
|
+
throw new Error(`GitLab token exchange failed (${response.status}): ${text3}`);
|
|
6751
|
+
}
|
|
6752
|
+
const raw = await response.json();
|
|
6753
|
+
const data = raw;
|
|
6754
|
+
return {
|
|
6755
|
+
accessToken: data.access_token,
|
|
6756
|
+
refreshToken: data.refresh_token,
|
|
6757
|
+
expiresIn: data.expires_in,
|
|
6758
|
+
tokenType: data.token_type ?? "Bearer",
|
|
6759
|
+
raw
|
|
6760
|
+
};
|
|
6761
|
+
}
|
|
6762
|
+
async function getUserInfo(accessToken) {
|
|
6763
|
+
const response = await fetch(USER_INFO_URL5, {
|
|
6764
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6765
|
+
});
|
|
6766
|
+
if (!response.ok) {
|
|
6767
|
+
const text3 = await response.text();
|
|
6768
|
+
throw new Error(`GitLab /api/v4/user fetch failed (${response.status}): ${text3}`);
|
|
6769
|
+
}
|
|
6770
|
+
const raw = await response.json();
|
|
6771
|
+
const data = raw;
|
|
6772
|
+
if (!data.id) {
|
|
6773
|
+
throw new Error("GitLab user response missing required field: id");
|
|
6774
|
+
}
|
|
6775
|
+
const email = data.email ?? data.public_email;
|
|
6776
|
+
if (!email) {
|
|
6777
|
+
throw new Error(
|
|
6778
|
+
"GitLab user response has no email. The account may have restricted email visibility."
|
|
6779
|
+
);
|
|
6780
|
+
}
|
|
6781
|
+
return {
|
|
6782
|
+
id: String(data.id),
|
|
6783
|
+
email,
|
|
6784
|
+
name: data.name ?? data.username,
|
|
6785
|
+
avatar: data.avatar_url,
|
|
6786
|
+
raw
|
|
6787
|
+
};
|
|
6788
|
+
}
|
|
6789
|
+
return {
|
|
6790
|
+
id: "gitlab",
|
|
6791
|
+
name: "GitLab",
|
|
6792
|
+
authorizationUrl: AUTHORIZATION_URL7,
|
|
6793
|
+
tokenUrl: TOKEN_URL7,
|
|
6794
|
+
userInfoUrl: USER_INFO_URL5,
|
|
6795
|
+
scopes,
|
|
6796
|
+
getAuthorizationUrl,
|
|
6797
|
+
exchangeCode,
|
|
6798
|
+
getUserInfo
|
|
6799
|
+
};
|
|
6800
|
+
}
|
|
6801
|
+
function mergeScopes8(defaults, extras) {
|
|
6802
|
+
if (!extras || extras.length === 0) return defaults;
|
|
6803
|
+
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6804
|
+
return [...merged];
|
|
6805
|
+
}
|
|
6806
|
+
|
|
6807
|
+
// src/auth/oauth/providers/google.ts
|
|
6808
|
+
var AUTHORIZATION_URL8 = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
6809
|
+
var TOKEN_URL8 = "https://oauth2.googleapis.com/token";
|
|
6810
|
+
var USER_INFO_URL6 = "https://www.googleapis.com/oauth2/v3/userinfo";
|
|
6811
|
+
var DEFAULT_SCOPES5 = ["openid", "email", "profile"];
|
|
6812
|
+
function createGoogleProvider(config) {
|
|
6813
|
+
const scopes = mergeScopes9(DEFAULT_SCOPES5, config.scopes);
|
|
6814
|
+
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6815
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6816
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6817
|
+
const params = new URLSearchParams({
|
|
6818
|
+
client_id: config.clientId,
|
|
6819
|
+
redirect_uri: effectiveRedirectUri,
|
|
6820
|
+
response_type: "code",
|
|
6821
|
+
scope: scopes.join(" "),
|
|
6822
|
+
state,
|
|
6823
|
+
code_challenge: codeChallenge,
|
|
6824
|
+
code_challenge_method: "S256",
|
|
6825
|
+
access_type: "offline",
|
|
6826
|
+
// request refresh token
|
|
6827
|
+
prompt: "consent"
|
|
6828
|
+
// always show consent to get refresh token reliably
|
|
6829
|
+
});
|
|
6830
|
+
return `${AUTHORIZATION_URL8}?${params.toString()}`;
|
|
6831
|
+
}
|
|
6832
|
+
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6833
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6834
|
+
const body = new URLSearchParams({
|
|
6835
|
+
grant_type: "authorization_code",
|
|
6836
|
+
client_id: config.clientId,
|
|
6837
|
+
client_secret: config.clientSecret,
|
|
6838
|
+
code: code2,
|
|
6839
|
+
code_verifier: codeVerifier,
|
|
6840
|
+
redirect_uri: effectiveRedirectUri
|
|
6841
|
+
});
|
|
6842
|
+
const response = await fetch(TOKEN_URL8, {
|
|
6843
|
+
method: "POST",
|
|
6844
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6845
|
+
body: body.toString()
|
|
6846
|
+
});
|
|
6847
|
+
if (!response.ok) {
|
|
6848
|
+
const text3 = await response.text();
|
|
6849
|
+
throw new Error(`Google token exchange failed (${response.status}): ${text3}`);
|
|
6850
|
+
}
|
|
6851
|
+
const raw = await response.json();
|
|
6852
|
+
const data = raw;
|
|
6853
|
+
return {
|
|
6854
|
+
accessToken: data.access_token,
|
|
6855
|
+
refreshToken: data.refresh_token,
|
|
6856
|
+
expiresIn: data.expires_in,
|
|
6857
|
+
tokenType: data.token_type ?? "Bearer",
|
|
6858
|
+
raw
|
|
6859
|
+
};
|
|
6860
|
+
}
|
|
6861
|
+
async function getUserInfo(accessToken) {
|
|
6862
|
+
const response = await fetch(USER_INFO_URL6, {
|
|
6863
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6864
|
+
});
|
|
6865
|
+
if (!response.ok) {
|
|
6866
|
+
const text3 = await response.text();
|
|
6867
|
+
throw new Error(`Google userinfo fetch failed (${response.status}): ${text3}`);
|
|
6868
|
+
}
|
|
6869
|
+
const raw = await response.json();
|
|
6870
|
+
const data = raw;
|
|
6871
|
+
if (!data.sub || !data.email) {
|
|
6872
|
+
throw new Error("Google userinfo response missing required fields: sub, email");
|
|
6873
|
+
}
|
|
6874
|
+
return {
|
|
6875
|
+
id: data.sub,
|
|
6876
|
+
email: data.email,
|
|
6877
|
+
name: data.name,
|
|
6878
|
+
avatar: data.picture,
|
|
6879
|
+
raw
|
|
6880
|
+
};
|
|
6881
|
+
}
|
|
6882
|
+
return {
|
|
6883
|
+
id: "google",
|
|
6884
|
+
name: "Google",
|
|
6885
|
+
authorizationUrl: AUTHORIZATION_URL8,
|
|
6886
|
+
tokenUrl: TOKEN_URL8,
|
|
6887
|
+
userInfoUrl: USER_INFO_URL6,
|
|
6888
|
+
scopes,
|
|
6889
|
+
getAuthorizationUrl,
|
|
6890
|
+
exchangeCode,
|
|
6891
|
+
getUserInfo
|
|
6892
|
+
};
|
|
6893
|
+
}
|
|
6894
|
+
function mergeScopes9(defaults, extras) {
|
|
6895
|
+
if (!extras || extras.length === 0) return defaults;
|
|
6896
|
+
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6897
|
+
return [...merged];
|
|
6898
|
+
}
|
|
6899
|
+
|
|
6900
|
+
// src/auth/oauth/providers/linkedin.ts
|
|
6901
|
+
var AUTHORIZATION_URL9 = "https://www.linkedin.com/oauth/v2/authorization";
|
|
6902
|
+
var TOKEN_URL9 = "https://www.linkedin.com/oauth/v2/accessToken";
|
|
6903
|
+
var USER_INFO_URL7 = "https://api.linkedin.com/v2/userinfo";
|
|
6904
|
+
var DEFAULT_SCOPES6 = ["openid", "profile", "email"];
|
|
6905
|
+
function createLinkedInProvider(config) {
|
|
6906
|
+
const scopes = mergeScopes10(DEFAULT_SCOPES6, config.scopes);
|
|
6907
|
+
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6908
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6909
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6910
|
+
const params = new URLSearchParams({
|
|
6911
|
+
response_type: "code",
|
|
6912
|
+
client_id: config.clientId,
|
|
6913
|
+
redirect_uri: effectiveRedirectUri,
|
|
6914
|
+
scope: scopes.join(" "),
|
|
6915
|
+
state,
|
|
6916
|
+
code_challenge: codeChallenge,
|
|
6917
|
+
code_challenge_method: "S256"
|
|
6918
|
+
});
|
|
6919
|
+
return `${AUTHORIZATION_URL9}?${params.toString()}`;
|
|
6920
|
+
}
|
|
6921
|
+
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6922
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6923
|
+
const body = new URLSearchParams({
|
|
6924
|
+
grant_type: "authorization_code",
|
|
6925
|
+
client_id: config.clientId,
|
|
6926
|
+
client_secret: config.clientSecret,
|
|
6927
|
+
code: code2,
|
|
6928
|
+
redirect_uri: effectiveRedirectUri,
|
|
6929
|
+
code_verifier: codeVerifier
|
|
6930
|
+
});
|
|
6931
|
+
const response = await fetch(TOKEN_URL9, {
|
|
6932
|
+
method: "POST",
|
|
6933
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6934
|
+
body: body.toString()
|
|
6935
|
+
});
|
|
6936
|
+
if (!response.ok) {
|
|
6937
|
+
const text3 = await response.text();
|
|
6938
|
+
throw new Error(`LinkedIn token exchange failed (${response.status}): ${text3}`);
|
|
6939
|
+
}
|
|
6940
|
+
const raw = await response.json();
|
|
6941
|
+
const data = raw;
|
|
6942
|
+
return {
|
|
6943
|
+
accessToken: data.access_token,
|
|
6944
|
+
refreshToken: data.refresh_token,
|
|
6945
|
+
expiresIn: data.expires_in,
|
|
6946
|
+
tokenType: data.token_type ?? "Bearer",
|
|
6947
|
+
raw
|
|
6948
|
+
};
|
|
6949
|
+
}
|
|
6950
|
+
async function getUserInfo(accessToken) {
|
|
6951
|
+
const response = await fetch(USER_INFO_URL7, {
|
|
6952
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6953
|
+
});
|
|
6954
|
+
if (!response.ok) {
|
|
6955
|
+
const text3 = await response.text();
|
|
6956
|
+
throw new Error(`LinkedIn /v2/userinfo fetch failed (${response.status}): ${text3}`);
|
|
6957
|
+
}
|
|
6958
|
+
const raw = await response.json();
|
|
6959
|
+
const data = raw;
|
|
6960
|
+
if (!data.sub) {
|
|
6961
|
+
throw new Error("LinkedIn userinfo response missing required field: sub");
|
|
6962
|
+
}
|
|
6963
|
+
if (!data.email) {
|
|
6964
|
+
throw new Error(
|
|
6965
|
+
"LinkedIn userinfo response has no email. Ensure the `email` and `openid` scopes are granted."
|
|
6966
|
+
);
|
|
6967
|
+
}
|
|
6968
|
+
const name = data.name ?? ([data.given_name, data.family_name].filter(Boolean).join(" ") || void 0);
|
|
6969
|
+
return {
|
|
6970
|
+
id: data.sub,
|
|
6971
|
+
email: data.email,
|
|
6972
|
+
name,
|
|
6973
|
+
avatar: data.picture,
|
|
6974
|
+
raw
|
|
6975
|
+
};
|
|
6976
|
+
}
|
|
6977
|
+
return {
|
|
6978
|
+
id: "linkedin",
|
|
6979
|
+
name: "LinkedIn",
|
|
6980
|
+
authorizationUrl: AUTHORIZATION_URL9,
|
|
6981
|
+
tokenUrl: TOKEN_URL9,
|
|
6982
|
+
userInfoUrl: USER_INFO_URL7,
|
|
6983
|
+
scopes,
|
|
6984
|
+
getAuthorizationUrl,
|
|
6985
|
+
exchangeCode,
|
|
6986
|
+
getUserInfo
|
|
6987
|
+
};
|
|
6988
|
+
}
|
|
6989
|
+
function mergeScopes10(defaults, extras) {
|
|
6990
|
+
if (!extras || extras.length === 0) return defaults;
|
|
6991
|
+
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6992
|
+
return [...merged];
|
|
6993
|
+
}
|
|
6994
|
+
|
|
6995
|
+
// src/auth/oauth/providers/microsoft.ts
|
|
6996
|
+
var AUTHORIZATION_URL10 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
|
|
6997
|
+
var TOKEN_URL10 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
|
|
6998
|
+
var USER_INFO_URL8 = "https://graph.microsoft.com/v1.0/me";
|
|
6999
|
+
var DEFAULT_SCOPES7 = ["openid", "profile", "email", "User.Read"];
|
|
7000
|
+
function createMicrosoftProvider(config) {
|
|
7001
|
+
const scopes = mergeScopes11(DEFAULT_SCOPES7, config.scopes);
|
|
7002
|
+
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
7003
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
7004
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
7005
|
+
const params = new URLSearchParams({
|
|
7006
|
+
client_id: config.clientId,
|
|
7007
|
+
redirect_uri: effectiveRedirectUri,
|
|
7008
|
+
response_type: "code",
|
|
7009
|
+
scope: scopes.join(" "),
|
|
7010
|
+
state,
|
|
7011
|
+
code_challenge: codeChallenge,
|
|
7012
|
+
code_challenge_method: "S256"
|
|
7013
|
+
});
|
|
7014
|
+
return `${AUTHORIZATION_URL10}?${params.toString()}`;
|
|
7015
|
+
}
|
|
7016
|
+
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
7017
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
7018
|
+
const body = new URLSearchParams({
|
|
7019
|
+
grant_type: "authorization_code",
|
|
7020
|
+
client_id: config.clientId,
|
|
7021
|
+
client_secret: config.clientSecret,
|
|
7022
|
+
code: code2,
|
|
7023
|
+
code_verifier: codeVerifier,
|
|
7024
|
+
redirect_uri: effectiveRedirectUri
|
|
7025
|
+
});
|
|
7026
|
+
const response = await fetch(TOKEN_URL10, {
|
|
7027
|
+
method: "POST",
|
|
7028
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
7029
|
+
body: body.toString()
|
|
7030
|
+
});
|
|
7031
|
+
if (!response.ok) {
|
|
7032
|
+
const text3 = await response.text();
|
|
7033
|
+
throw new Error(`Microsoft token exchange failed (${response.status}): ${text3}`);
|
|
7034
|
+
}
|
|
7035
|
+
const raw = await response.json();
|
|
7036
|
+
const data = raw;
|
|
7037
|
+
return {
|
|
7038
|
+
accessToken: data.access_token,
|
|
7039
|
+
refreshToken: data.refresh_token,
|
|
7040
|
+
expiresIn: data.expires_in,
|
|
7041
|
+
tokenType: data.token_type ?? "Bearer",
|
|
7042
|
+
raw
|
|
7043
|
+
};
|
|
7044
|
+
}
|
|
7045
|
+
async function getUserInfo(accessToken) {
|
|
7046
|
+
const response = await fetch(USER_INFO_URL8, {
|
|
7047
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
7048
|
+
});
|
|
7049
|
+
if (!response.ok) {
|
|
7050
|
+
const text3 = await response.text();
|
|
7051
|
+
throw new Error(`Microsoft Graph /me fetch failed (${response.status}): ${text3}`);
|
|
7052
|
+
}
|
|
7053
|
+
const raw = await response.json();
|
|
7054
|
+
const data = raw;
|
|
7055
|
+
if (!data.id) {
|
|
7056
|
+
throw new Error("Microsoft Graph /me response missing required field: id");
|
|
7057
|
+
}
|
|
7058
|
+
const email = data.mail ?? data.userPrincipalName;
|
|
7059
|
+
if (!email) {
|
|
7060
|
+
throw new Error(
|
|
7061
|
+
"Microsoft Graph /me response has no email or userPrincipalName. Ensure the `email` and `User.Read` scopes are granted."
|
|
7062
|
+
);
|
|
7063
|
+
}
|
|
7064
|
+
const name = data.displayName ?? ([data.givenName, data.surname].filter(Boolean).join(" ") || void 0);
|
|
7065
|
+
return {
|
|
7066
|
+
id: data.id,
|
|
7067
|
+
email,
|
|
7068
|
+
name,
|
|
7069
|
+
avatar: void 0,
|
|
7070
|
+
// Graph photo requires a separate /me/photo/$value call
|
|
7071
|
+
raw
|
|
7072
|
+
};
|
|
7073
|
+
}
|
|
7074
|
+
return {
|
|
7075
|
+
id: "microsoft",
|
|
7076
|
+
name: "Microsoft",
|
|
7077
|
+
authorizationUrl: AUTHORIZATION_URL10,
|
|
7078
|
+
tokenUrl: TOKEN_URL10,
|
|
7079
|
+
userInfoUrl: USER_INFO_URL8,
|
|
7080
|
+
scopes,
|
|
7081
|
+
getAuthorizationUrl,
|
|
7082
|
+
exchangeCode,
|
|
7083
|
+
getUserInfo
|
|
7084
|
+
};
|
|
7085
|
+
}
|
|
7086
|
+
function mergeScopes11(defaults, extras) {
|
|
7087
|
+
if (!extras || extras.length === 0) return defaults;
|
|
7088
|
+
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
7089
|
+
return [...merged];
|
|
7090
|
+
}
|
|
7091
|
+
|
|
7092
|
+
// src/auth/oauth/providers/notion.ts
|
|
7093
|
+
var AUTHORIZATION_URL11 = "https://api.notion.com/v1/oauth/authorize";
|
|
7094
|
+
var TOKEN_URL11 = "https://api.notion.com/v1/oauth/token";
|
|
7095
|
+
var NOTION_VERSION = "2022-06-28";
|
|
7096
|
+
var DEFAULT_NOTION_SCOPES = [];
|
|
7097
|
+
function normalizeProfile5(raw) {
|
|
7098
|
+
const tokenData = raw;
|
|
7099
|
+
const user = tokenData?.owner?.user;
|
|
7100
|
+
if (!user?.id) {
|
|
7101
|
+
throw new Error(
|
|
7102
|
+
"Notion token response missing owner.user.id. Ensure the integration is authorized by a person, not a workspace bot."
|
|
7103
|
+
);
|
|
7104
|
+
}
|
|
7105
|
+
return {
|
|
7106
|
+
id: user.id,
|
|
7107
|
+
email: user.person?.email,
|
|
7108
|
+
name: user.name,
|
|
7109
|
+
avatar: user.avatar_url ?? void 0,
|
|
7110
|
+
raw
|
|
7111
|
+
};
|
|
7112
|
+
}
|
|
7113
|
+
function createNotionProvider(config) {
|
|
7114
|
+
const scopes = [];
|
|
7115
|
+
let lastTokenRaw = null;
|
|
7116
|
+
async function getAuthorizationUrl(state, _codeVerifier, redirectUri) {
|
|
7117
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
7118
|
+
const params = new URLSearchParams({
|
|
7119
|
+
client_id: config.clientId,
|
|
7120
|
+
redirect_uri: effectiveRedirectUri,
|
|
7121
|
+
response_type: "code",
|
|
7122
|
+
owner: "user",
|
|
7123
|
+
state
|
|
7124
|
+
});
|
|
7125
|
+
return `${AUTHORIZATION_URL11}?${params.toString()}`;
|
|
7126
|
+
}
|
|
7127
|
+
async function exchangeCode(code2, _codeVerifier, redirectUri) {
|
|
7128
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
7129
|
+
const credentials = btoa(`${config.clientId}:${config.clientSecret}`);
|
|
7130
|
+
const response = await fetch(TOKEN_URL11, {
|
|
7131
|
+
method: "POST",
|
|
7132
|
+
headers: {
|
|
7133
|
+
"Content-Type": "application/json",
|
|
7134
|
+
Authorization: `Basic ${credentials}`,
|
|
7135
|
+
"Notion-Version": NOTION_VERSION
|
|
7136
|
+
},
|
|
7137
|
+
body: JSON.stringify({
|
|
7138
|
+
grant_type: "authorization_code",
|
|
7139
|
+
code: code2,
|
|
7140
|
+
redirect_uri: effectiveRedirectUri
|
|
7141
|
+
})
|
|
7142
|
+
});
|
|
7143
|
+
if (!response.ok) {
|
|
7144
|
+
const text3 = await response.text();
|
|
7145
|
+
throw new Error(`Notion token exchange failed (${response.status}): ${text3}`);
|
|
7146
|
+
}
|
|
7147
|
+
const raw = await response.json();
|
|
7148
|
+
const data = raw;
|
|
7149
|
+
lastTokenRaw = raw;
|
|
7150
|
+
return {
|
|
7151
|
+
accessToken: data.access_token,
|
|
7152
|
+
tokenType: data.token_type ?? "Bearer",
|
|
7153
|
+
raw
|
|
7154
|
+
};
|
|
7155
|
+
}
|
|
7156
|
+
async function getUserInfo(_accessToken) {
|
|
7157
|
+
if (!lastTokenRaw) {
|
|
7158
|
+
throw new Error(
|
|
7159
|
+
"Notion getUserInfo called before exchangeCode. Call exchangeCode first to obtain the token response."
|
|
7160
|
+
);
|
|
7161
|
+
}
|
|
7162
|
+
const tokenData = lastTokenRaw;
|
|
7163
|
+
const user = tokenData?.owner?.user;
|
|
7164
|
+
if (!user?.id) {
|
|
7165
|
+
throw new Error(
|
|
7166
|
+
"Notion token response missing owner.user.id. Ensure the integration is authorized by a person, not a workspace bot."
|
|
7167
|
+
);
|
|
7168
|
+
}
|
|
7169
|
+
const email = user.person?.email;
|
|
7170
|
+
const avatar = user.avatar_url ?? void 0;
|
|
7171
|
+
return {
|
|
7172
|
+
id: user.id,
|
|
7173
|
+
email,
|
|
7174
|
+
name: user.name,
|
|
7175
|
+
avatar,
|
|
7176
|
+
raw: lastTokenRaw
|
|
7177
|
+
};
|
|
7178
|
+
}
|
|
7179
|
+
return {
|
|
7180
|
+
id: "notion",
|
|
7181
|
+
name: "Notion",
|
|
7182
|
+
authorizationUrl: AUTHORIZATION_URL11,
|
|
7183
|
+
tokenUrl: TOKEN_URL11,
|
|
7184
|
+
// No separate UserInfo URL; identity comes from the token response.
|
|
7185
|
+
userInfoUrl: void 0,
|
|
7186
|
+
scopes,
|
|
7187
|
+
getAuthorizationUrl,
|
|
7188
|
+
exchangeCode,
|
|
7189
|
+
getUserInfo
|
|
7190
|
+
};
|
|
7191
|
+
}
|
|
7192
|
+
|
|
7193
|
+
// src/auth/oauth/providers/presets.ts
|
|
7194
|
+
function facebookProvider(clientId, clientSecret, scopes) {
|
|
7195
|
+
return genericOIDC({
|
|
7196
|
+
id: "facebook",
|
|
7197
|
+
name: "Facebook",
|
|
7198
|
+
issuer: "https://www.facebook.com",
|
|
7199
|
+
clientId,
|
|
7200
|
+
clientSecret,
|
|
7201
|
+
scopes: scopes ?? ["email", "public_profile"],
|
|
7202
|
+
authorizationUrl: "https://www.facebook.com/v18.0/dialog/oauth",
|
|
7203
|
+
tokenUrl: "https://graph.facebook.com/v18.0/oauth/access_token",
|
|
7204
|
+
userinfoUrl: "https://graph.facebook.com/me?fields=id,email,name,picture"
|
|
7205
|
+
});
|
|
7206
|
+
}
|
|
7207
|
+
function spotifyProvider(clientId, clientSecret, scopes) {
|
|
7208
|
+
return genericOIDC({
|
|
7209
|
+
id: "spotify",
|
|
7210
|
+
name: "Spotify",
|
|
7211
|
+
issuer: "https://accounts.spotify.com",
|
|
7212
|
+
clientId,
|
|
7213
|
+
clientSecret,
|
|
7214
|
+
scopes: scopes ?? ["user-read-email", "user-read-private"],
|
|
7215
|
+
authorizationUrl: "https://accounts.spotify.com/authorize",
|
|
7216
|
+
tokenUrl: "https://accounts.spotify.com/api/token",
|
|
7217
|
+
userinfoUrl: "https://api.spotify.com/v1/me"
|
|
7218
|
+
});
|
|
7219
|
+
}
|
|
7220
|
+
function twitchProvider(clientId, clientSecret, scopes) {
|
|
7221
|
+
return genericOIDC({
|
|
7222
|
+
id: "twitch",
|
|
7223
|
+
name: "Twitch",
|
|
7224
|
+
issuer: "https://id.twitch.tv/oauth2",
|
|
7225
|
+
clientId,
|
|
7226
|
+
clientSecret,
|
|
7227
|
+
scopes: scopes ?? ["openid", "user:read:email"],
|
|
7228
|
+
authorizationUrl: "https://id.twitch.tv/oauth2/authorize",
|
|
7229
|
+
tokenUrl: "https://id.twitch.tv/oauth2/token",
|
|
7230
|
+
userinfoUrl: "https://id.twitch.tv/oauth2/userinfo"
|
|
7231
|
+
});
|
|
7232
|
+
}
|
|
7233
|
+
function redditProvider(clientId, clientSecret, scopes) {
|
|
7234
|
+
return genericOIDC({
|
|
7235
|
+
id: "reddit",
|
|
7236
|
+
name: "Reddit",
|
|
7237
|
+
issuer: "https://www.reddit.com",
|
|
7238
|
+
clientId,
|
|
7239
|
+
clientSecret,
|
|
7240
|
+
scopes: scopes ?? ["identity"],
|
|
7241
|
+
authorizationUrl: "https://www.reddit.com/api/v1/authorize",
|
|
7242
|
+
tokenUrl: "https://www.reddit.com/api/v1/access_token",
|
|
7243
|
+
userinfoUrl: "https://oauth.reddit.com/api/v1/me"
|
|
7244
|
+
});
|
|
7245
|
+
}
|
|
7246
|
+
function dropboxProvider(clientId, clientSecret, scopes) {
|
|
7247
|
+
return genericOIDC({
|
|
7248
|
+
id: "dropbox",
|
|
7249
|
+
name: "Dropbox",
|
|
7250
|
+
issuer: "https://www.dropbox.com",
|
|
7251
|
+
clientId,
|
|
7252
|
+
clientSecret,
|
|
7253
|
+
scopes: scopes ?? ["account_info.read"],
|
|
7254
|
+
authorizationUrl: "https://www.dropbox.com/oauth2/authorize",
|
|
7255
|
+
tokenUrl: "https://api.dropboxapi.com/oauth2/token",
|
|
7256
|
+
userinfoUrl: "https://api.dropboxapi.com/2/users/get_current_account"
|
|
7257
|
+
});
|
|
7258
|
+
}
|
|
7259
|
+
function zoomProvider(clientId, clientSecret, scopes) {
|
|
7260
|
+
return genericOIDC({
|
|
7261
|
+
id: "zoom",
|
|
7262
|
+
name: "Zoom",
|
|
7263
|
+
issuer: "https://zoom.us",
|
|
7264
|
+
clientId,
|
|
7265
|
+
clientSecret,
|
|
7266
|
+
scopes: scopes ?? ["openid", "profile", "email"],
|
|
7267
|
+
authorizationUrl: "https://zoom.us/oauth/authorize",
|
|
7268
|
+
tokenUrl: "https://zoom.us/oauth/token",
|
|
7269
|
+
userinfoUrl: "https://api.zoom.us/v2/users/me"
|
|
7270
|
+
});
|
|
7271
|
+
}
|
|
7272
|
+
function notionProvider(clientId, clientSecret, scopes) {
|
|
7273
|
+
return genericOIDC({
|
|
7274
|
+
id: "notion",
|
|
7275
|
+
name: "Notion",
|
|
7276
|
+
issuer: "https://api.notion.com",
|
|
7277
|
+
clientId,
|
|
7278
|
+
clientSecret,
|
|
7279
|
+
scopes: scopes ?? [],
|
|
7280
|
+
authorizationUrl: "https://api.notion.com/v1/oauth/authorize",
|
|
7281
|
+
tokenUrl: "https://api.notion.com/v1/oauth/token",
|
|
7282
|
+
userinfoUrl: "https://api.notion.com/v1/users/me"
|
|
7283
|
+
});
|
|
7284
|
+
}
|
|
7285
|
+
function figmaProvider(clientId, clientSecret, scopes) {
|
|
7286
|
+
return genericOIDC({
|
|
7287
|
+
id: "figma",
|
|
7288
|
+
name: "Figma",
|
|
7289
|
+
issuer: "https://www.figma.com",
|
|
7290
|
+
clientId,
|
|
7291
|
+
clientSecret,
|
|
7292
|
+
scopes: scopes ?? ["file_read"],
|
|
7293
|
+
authorizationUrl: "https://www.figma.com/oauth",
|
|
7294
|
+
tokenUrl: "https://api.figma.com/v1/oauth/token",
|
|
7295
|
+
userinfoUrl: "https://api.figma.com/v1/me"
|
|
7296
|
+
});
|
|
7297
|
+
}
|
|
7298
|
+
function bitbucketProvider(clientId, clientSecret, scopes) {
|
|
7299
|
+
return genericOIDC({
|
|
7300
|
+
id: "bitbucket",
|
|
7301
|
+
name: "Bitbucket",
|
|
7302
|
+
issuer: "https://bitbucket.org",
|
|
7303
|
+
clientId,
|
|
7304
|
+
clientSecret,
|
|
7305
|
+
scopes: scopes ?? ["account", "email"],
|
|
7306
|
+
authorizationUrl: "https://bitbucket.org/site/oauth2/authorize",
|
|
7307
|
+
tokenUrl: "https://bitbucket.org/site/oauth2/access_token",
|
|
7308
|
+
userinfoUrl: "https://api.bitbucket.org/2.0/user"
|
|
7309
|
+
});
|
|
7310
|
+
}
|
|
7311
|
+
function atlassianProvider(clientId, clientSecret, scopes) {
|
|
7312
|
+
return genericOIDC({
|
|
7313
|
+
id: "atlassian",
|
|
7314
|
+
name: "Atlassian",
|
|
7315
|
+
issuer: "https://auth.atlassian.com",
|
|
7316
|
+
clientId,
|
|
7317
|
+
clientSecret,
|
|
7318
|
+
scopes: scopes ?? ["read:me", "offline_access"],
|
|
7319
|
+
authorizationUrl: "https://auth.atlassian.com/authorize",
|
|
7320
|
+
tokenUrl: "https://auth.atlassian.com/oauth/token",
|
|
7321
|
+
userinfoUrl: "https://api.atlassian.com/me"
|
|
7322
|
+
});
|
|
7323
|
+
}
|
|
7324
|
+
function yahooProvider(clientId, clientSecret, scopes) {
|
|
7325
|
+
return genericOIDC({
|
|
7326
|
+
id: "yahoo",
|
|
7327
|
+
name: "Yahoo",
|
|
7328
|
+
issuer: "https://api.login.yahoo.com",
|
|
7329
|
+
clientId,
|
|
7330
|
+
clientSecret,
|
|
7331
|
+
scopes: scopes ?? ["openid", "profile", "email"],
|
|
7332
|
+
authorizationUrl: "https://api.login.yahoo.com/oauth2/request_auth",
|
|
7333
|
+
tokenUrl: "https://api.login.yahoo.com/oauth2/get_token",
|
|
7334
|
+
userinfoUrl: "https://api.login.yahoo.com/openid/v1/userinfo"
|
|
7335
|
+
});
|
|
7336
|
+
}
|
|
7337
|
+
function lineProvider(clientId, clientSecret, scopes) {
|
|
7338
|
+
return genericOIDC({
|
|
7339
|
+
id: "line",
|
|
7340
|
+
name: "LINE",
|
|
7341
|
+
issuer: "https://access.line.me",
|
|
7342
|
+
clientId,
|
|
7343
|
+
clientSecret,
|
|
7344
|
+
scopes: scopes ?? ["openid", "profile", "email"],
|
|
7345
|
+
authorizationUrl: "https://access.line.me/oauth2/v2.1/authorize",
|
|
7346
|
+
tokenUrl: "https://api.line.me/oauth2/v2.1/token",
|
|
7347
|
+
userinfoUrl: "https://api.line.me/v2/profile"
|
|
7348
|
+
});
|
|
7349
|
+
}
|
|
7350
|
+
function coinbaseProvider(clientId, clientSecret, scopes) {
|
|
7351
|
+
return genericOIDC({
|
|
7352
|
+
id: "coinbase",
|
|
7353
|
+
name: "Coinbase",
|
|
7354
|
+
issuer: "https://login.coinbase.com",
|
|
7355
|
+
clientId,
|
|
7356
|
+
clientSecret,
|
|
7357
|
+
scopes: scopes ?? ["wallet:user:read", "wallet:user:email"],
|
|
7358
|
+
authorizationUrl: "https://login.coinbase.com/oauth2/auth",
|
|
7359
|
+
tokenUrl: "https://login.coinbase.com/oauth2/token",
|
|
7360
|
+
userinfoUrl: "https://api.coinbase.com/v2/user"
|
|
7361
|
+
});
|
|
7362
|
+
}
|
|
7363
|
+
function tiktokProvider(clientId, clientSecret, scopes) {
|
|
7364
|
+
return genericOIDC({
|
|
7365
|
+
id: "tiktok",
|
|
7366
|
+
name: "TikTok",
|
|
7367
|
+
issuer: "https://www.tiktok.com",
|
|
7368
|
+
clientId,
|
|
7369
|
+
clientSecret,
|
|
7370
|
+
scopes: scopes ?? ["user.info.basic"],
|
|
7371
|
+
authorizationUrl: "https://www.tiktok.com/v2/auth/authorize/",
|
|
7372
|
+
tokenUrl: "https://open.tiktokapis.com/v2/oauth/token/",
|
|
7373
|
+
userinfoUrl: "https://open.tiktokapis.com/v2/user/info/"
|
|
7374
|
+
});
|
|
7375
|
+
}
|
|
7376
|
+
function paypalProvider(clientId, clientSecret, scopes) {
|
|
7377
|
+
return genericOIDC({
|
|
7378
|
+
id: "paypal",
|
|
7379
|
+
name: "PayPal",
|
|
7380
|
+
issuer: "https://www.paypal.com",
|
|
7381
|
+
clientId,
|
|
7382
|
+
clientSecret,
|
|
7383
|
+
scopes: scopes ?? ["openid", "email"],
|
|
7384
|
+
authorizationUrl: "https://www.paypal.com/signin/authorize",
|
|
7385
|
+
tokenUrl: "https://api-m.paypal.com/v1/oauth2/token",
|
|
7386
|
+
userinfoUrl: "https://api-m.paypal.com/v1/identity/openidconnect/userinfo?schema=openid"
|
|
7387
|
+
});
|
|
7388
|
+
}
|
|
7389
|
+
function salesforceProvider(clientId, clientSecret, scopes) {
|
|
7390
|
+
return genericOIDC({
|
|
7391
|
+
id: "salesforce",
|
|
7392
|
+
name: "Salesforce",
|
|
7393
|
+
issuer: "https://login.salesforce.com",
|
|
7394
|
+
clientId,
|
|
7395
|
+
clientSecret,
|
|
7396
|
+
scopes: scopes ?? ["openid", "email", "profile"],
|
|
7397
|
+
authorizationUrl: "https://login.salesforce.com/services/oauth2/authorize",
|
|
7398
|
+
tokenUrl: "https://login.salesforce.com/services/oauth2/token",
|
|
7399
|
+
userinfoUrl: "https://login.salesforce.com/services/oauth2/userinfo"
|
|
7400
|
+
});
|
|
7401
|
+
}
|
|
7402
|
+
function vkProvider(clientId, clientSecret, scopes) {
|
|
7403
|
+
return genericOIDC({
|
|
7404
|
+
id: "vk",
|
|
7405
|
+
name: "VK",
|
|
7406
|
+
issuer: "https://id.vk.com",
|
|
7407
|
+
clientId,
|
|
7408
|
+
clientSecret,
|
|
7409
|
+
scopes: scopes ?? ["email"],
|
|
7410
|
+
authorizationUrl: "https://id.vk.com/authorize",
|
|
7411
|
+
tokenUrl: "https://id.vk.com/oauth2/auth",
|
|
7412
|
+
userinfoUrl: "https://id.vk.com/oauth2/user_info"
|
|
7413
|
+
});
|
|
7414
|
+
}
|
|
7415
|
+
function kakaoProvider(clientId, clientSecret, scopes) {
|
|
7416
|
+
return genericOIDC({
|
|
7417
|
+
id: "kakao",
|
|
7418
|
+
name: "Kakao",
|
|
7419
|
+
issuer: "https://kauth.kakao.com",
|
|
7420
|
+
clientId,
|
|
7421
|
+
clientSecret,
|
|
7422
|
+
scopes: scopes ?? ["account_email", "profile_nickname"],
|
|
7423
|
+
authorizationUrl: "https://kauth.kakao.com/oauth/authorize",
|
|
7424
|
+
tokenUrl: "https://kauth.kakao.com/oauth/token",
|
|
7425
|
+
userinfoUrl: "https://kapi.kakao.com/v2/user/me"
|
|
7426
|
+
});
|
|
7427
|
+
}
|
|
7428
|
+
function naverProvider(clientId, clientSecret, scopes) {
|
|
7429
|
+
return genericOIDC({
|
|
7430
|
+
id: "naver",
|
|
7431
|
+
name: "Naver",
|
|
7432
|
+
issuer: "https://nid.naver.com",
|
|
7433
|
+
clientId,
|
|
7434
|
+
clientSecret,
|
|
7435
|
+
scopes: scopes ?? ["email", "profile"],
|
|
7436
|
+
authorizationUrl: "https://nid.naver.com/oauth2.0/authorize",
|
|
7437
|
+
tokenUrl: "https://nid.naver.com/oauth2.0/token",
|
|
7438
|
+
userinfoUrl: "https://openapi.naver.com/v1/nid/me"
|
|
7439
|
+
});
|
|
7440
|
+
}
|
|
7441
|
+
function huggingfaceProvider(clientId, clientSecret, scopes) {
|
|
7442
|
+
return genericOIDC({
|
|
7443
|
+
id: "huggingface",
|
|
7444
|
+
name: "Hugging Face",
|
|
7445
|
+
issuer: "https://huggingface.co",
|
|
7446
|
+
clientId,
|
|
7447
|
+
clientSecret,
|
|
7448
|
+
scopes: scopes ?? ["openid", "profile", "email"],
|
|
7449
|
+
authorizationUrl: "https://huggingface.co/oauth/authorize",
|
|
7450
|
+
tokenUrl: "https://huggingface.co/oauth/token",
|
|
7451
|
+
userinfoUrl: "https://huggingface.co/oauth/userinfo"
|
|
7452
|
+
});
|
|
7453
|
+
}
|
|
7454
|
+
function robloxProvider(clientId, clientSecret, scopes) {
|
|
7455
|
+
return genericOIDC({
|
|
7456
|
+
id: "roblox",
|
|
7457
|
+
name: "Roblox",
|
|
7458
|
+
issuer: "https://apis.roblox.com/oauth",
|
|
7459
|
+
clientId,
|
|
7460
|
+
clientSecret,
|
|
7461
|
+
scopes: scopes ?? ["openid", "profile"],
|
|
7462
|
+
authorizationUrl: "https://apis.roblox.com/oauth/v1/authorize",
|
|
7463
|
+
tokenUrl: "https://apis.roblox.com/oauth/v1/token",
|
|
7464
|
+
userinfoUrl: "https://apis.roblox.com/oauth/v1/userinfo"
|
|
7465
|
+
});
|
|
7466
|
+
}
|
|
7467
|
+
function vercelProvider(clientId, clientSecret, scopes) {
|
|
7468
|
+
return genericOIDC({
|
|
7469
|
+
id: "vercel",
|
|
7470
|
+
name: "Vercel",
|
|
7471
|
+
issuer: "https://vercel.com",
|
|
7472
|
+
clientId,
|
|
7473
|
+
clientSecret,
|
|
7474
|
+
scopes: scopes ?? ["openid", "email", "profile"],
|
|
7475
|
+
authorizationUrl: "https://vercel.com/integrations/oauth/authorize",
|
|
7476
|
+
tokenUrl: "https://api.vercel.com/v2/oauth/access_token",
|
|
7477
|
+
userinfoUrl: "https://api.vercel.com/v2/user"
|
|
7478
|
+
});
|
|
7479
|
+
}
|
|
7480
|
+
function linearProvider(clientId, clientSecret, scopes) {
|
|
7481
|
+
return genericOIDC({
|
|
7482
|
+
id: "linear",
|
|
7483
|
+
name: "Linear",
|
|
7484
|
+
issuer: "https://linear.app",
|
|
7485
|
+
clientId,
|
|
7486
|
+
clientSecret,
|
|
7487
|
+
scopes: scopes ?? ["read"],
|
|
7488
|
+
authorizationUrl: "https://linear.app/oauth/authorize",
|
|
7489
|
+
tokenUrl: "https://api.linear.app/oauth/token",
|
|
7490
|
+
userinfoUrl: "https://api.linear.app/graphql"
|
|
7491
|
+
});
|
|
7492
|
+
}
|
|
7493
|
+
function railwayProvider(clientId, clientSecret, scopes) {
|
|
7494
|
+
return genericOIDC({
|
|
7495
|
+
id: "railway",
|
|
7496
|
+
name: "Railway",
|
|
7497
|
+
issuer: "https://railway.com",
|
|
7498
|
+
clientId,
|
|
7499
|
+
clientSecret,
|
|
7500
|
+
scopes: scopes ?? ["read:user", "read:project"],
|
|
7501
|
+
authorizationUrl: "https://railway.com/oauth/authorize",
|
|
7502
|
+
tokenUrl: "https://railway.com/oauth/token",
|
|
7503
|
+
userinfoUrl: "https://backboard.railway.com/graphql/v2"
|
|
7504
|
+
});
|
|
7505
|
+
}
|
|
7506
|
+
function kickProvider(clientId, clientSecret, scopes) {
|
|
7507
|
+
return genericOIDC({
|
|
7508
|
+
id: "kick",
|
|
7509
|
+
name: "Kick",
|
|
7510
|
+
issuer: "https://id.kick.com",
|
|
7511
|
+
clientId,
|
|
7512
|
+
clientSecret,
|
|
7513
|
+
scopes: scopes ?? ["user:read"],
|
|
7514
|
+
authorizationUrl: "https://id.kick.com/oauth/authorize",
|
|
7515
|
+
tokenUrl: "https://id.kick.com/oauth/token",
|
|
7516
|
+
userinfoUrl: "https://id.kick.com/oauth/userinfo"
|
|
7517
|
+
});
|
|
7518
|
+
}
|
|
7519
|
+
function wechatProvider(clientId, clientSecret, scopes) {
|
|
7520
|
+
return genericOIDC({
|
|
7521
|
+
id: "wechat",
|
|
7522
|
+
name: "WeChat",
|
|
7523
|
+
issuer: "https://open.weixin.qq.com",
|
|
7524
|
+
clientId,
|
|
7525
|
+
clientSecret,
|
|
7526
|
+
scopes: scopes ?? ["snsapi_login"],
|
|
7527
|
+
authorizationUrl: "https://open.weixin.qq.com/connect/qrconnect",
|
|
7528
|
+
tokenUrl: "https://api.weixin.qq.com/sns/oauth2/access_token",
|
|
7529
|
+
userinfoUrl: "https://api.weixin.qq.com/sns/userinfo"
|
|
7530
|
+
});
|
|
7531
|
+
}
|
|
7532
|
+
function polarProvider(clientId, clientSecret, scopes) {
|
|
7533
|
+
return genericOIDC({
|
|
7534
|
+
id: "polar",
|
|
7535
|
+
name: "Polar",
|
|
7536
|
+
issuer: "https://polar.sh",
|
|
7537
|
+
clientId,
|
|
7538
|
+
clientSecret,
|
|
7539
|
+
scopes: scopes ?? ["openid", "email", "profile"],
|
|
7540
|
+
authorizationUrl: "https://polar.sh/oauth2/authorize",
|
|
7541
|
+
tokenUrl: "https://api.polar.sh/v1/oauth2/token",
|
|
7542
|
+
userinfoUrl: "https://api.polar.sh/v1/oauth2/userinfo"
|
|
7543
|
+
});
|
|
7544
|
+
}
|
|
7545
|
+
function auth0Provider(domain, clientId, clientSecret, scopes) {
|
|
7546
|
+
const issuer = `https://${domain.replace(/^https?:\/\//, "")}`;
|
|
7547
|
+
return genericOIDC({
|
|
7548
|
+
id: "auth0",
|
|
7549
|
+
name: "Auth0",
|
|
7550
|
+
issuer,
|
|
7551
|
+
clientId,
|
|
7552
|
+
clientSecret,
|
|
7553
|
+
scopes
|
|
7554
|
+
});
|
|
7555
|
+
}
|
|
7556
|
+
function oktaProvider(domain, clientId, clientSecret, scopes) {
|
|
7557
|
+
const issuer = `https://${domain.replace(/^https?:\/\//, "")}/oauth2/default`;
|
|
7558
|
+
return genericOIDC({
|
|
7559
|
+
id: "okta",
|
|
7560
|
+
name: "Okta",
|
|
7561
|
+
issuer,
|
|
7562
|
+
clientId,
|
|
7563
|
+
clientSecret,
|
|
7564
|
+
scopes
|
|
7565
|
+
});
|
|
7566
|
+
}
|
|
7567
|
+
function cognitoProvider(domain, clientId, clientSecret, scopes) {
|
|
7568
|
+
const host = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
7569
|
+
const issuer = `https://${host}`;
|
|
7570
|
+
return genericOIDC({
|
|
7571
|
+
id: "cognito",
|
|
7572
|
+
name: "AWS Cognito",
|
|
7573
|
+
issuer,
|
|
7574
|
+
clientId,
|
|
7575
|
+
clientSecret,
|
|
7576
|
+
scopes: scopes ?? ["openid", "email", "profile"],
|
|
7577
|
+
authorizationUrl: `${issuer}/oauth2/authorize`,
|
|
7578
|
+
tokenUrl: `${issuer}/oauth2/token`,
|
|
7579
|
+
userinfoUrl: `${issuer}/oauth2/userInfo`
|
|
7580
|
+
});
|
|
7581
|
+
}
|
|
7582
|
+
|
|
7583
|
+
// src/auth/oauth/providers/reddit.ts
|
|
7584
|
+
var AUTHORIZATION_URL12 = "https://www.reddit.com/api/v1/authorize";
|
|
7585
|
+
var TOKEN_URL12 = "https://www.reddit.com/api/v1/access_token";
|
|
7586
|
+
var USER_INFO_URL9 = "https://oauth.reddit.com/api/v1/me";
|
|
7587
|
+
var DEFAULT_USER_AGENT = "web:kavachos-oauth:v1 (by /u/kavachos)";
|
|
7588
|
+
var DEFAULT_REDDIT_SCOPES = ["identity"];
|
|
7589
|
+
var DEFAULT_SCOPES8 = DEFAULT_REDDIT_SCOPES;
|
|
7590
|
+
function createRedditProvider(config) {
|
|
7591
|
+
const scopes = mergeScopes12(DEFAULT_SCOPES8, config.scopes);
|
|
7592
|
+
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
7593
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
7594
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
7595
|
+
const params = new URLSearchParams({
|
|
7596
|
+
client_id: config.clientId,
|
|
7597
|
+
redirect_uri: effectiveRedirectUri,
|
|
7598
|
+
response_type: "code",
|
|
7599
|
+
scope: scopes.join(" "),
|
|
7600
|
+
state,
|
|
7601
|
+
code_challenge: codeChallenge,
|
|
7602
|
+
code_challenge_method: "S256",
|
|
7603
|
+
// Reddit requires duration=permanent to receive a refresh token.
|
|
7604
|
+
duration: "permanent"
|
|
7605
|
+
});
|
|
7606
|
+
return `${AUTHORIZATION_URL12}?${params.toString()}`;
|
|
7607
|
+
}
|
|
7608
|
+
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
7609
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
7610
|
+
const credentials = btoa(`${config.clientId}:${config.clientSecret}`);
|
|
7611
|
+
const body = new URLSearchParams({
|
|
7612
|
+
grant_type: "authorization_code",
|
|
7613
|
+
code: code2,
|
|
7614
|
+
redirect_uri: effectiveRedirectUri,
|
|
7615
|
+
code_verifier: codeVerifier
|
|
7616
|
+
});
|
|
7617
|
+
const response = await fetch(TOKEN_URL12, {
|
|
7618
|
+
method: "POST",
|
|
7619
|
+
headers: {
|
|
7620
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
7621
|
+
Authorization: `Basic ${credentials}`,
|
|
7622
|
+
"User-Agent": DEFAULT_USER_AGENT
|
|
7623
|
+
},
|
|
7624
|
+
body: body.toString()
|
|
7625
|
+
});
|
|
7626
|
+
if (!response.ok) {
|
|
7627
|
+
const text3 = await response.text();
|
|
7628
|
+
throw new Error(`Reddit token exchange failed (${response.status}): ${text3}`);
|
|
7629
|
+
}
|
|
7630
|
+
const raw = await response.json();
|
|
7631
|
+
const data = raw;
|
|
7632
|
+
return {
|
|
7633
|
+
accessToken: data.access_token,
|
|
7634
|
+
refreshToken: data.refresh_token,
|
|
7635
|
+
expiresIn: data.expires_in,
|
|
7636
|
+
tokenType: data.token_type ?? "Bearer",
|
|
7637
|
+
raw
|
|
7638
|
+
};
|
|
7639
|
+
}
|
|
7640
|
+
async function getUserInfo(accessToken) {
|
|
7641
|
+
const response = await fetch(USER_INFO_URL9, {
|
|
7642
|
+
headers: {
|
|
7643
|
+
Authorization: `Bearer ${accessToken}`,
|
|
7644
|
+
"User-Agent": DEFAULT_USER_AGENT
|
|
7645
|
+
}
|
|
7646
|
+
});
|
|
7647
|
+
if (!response.ok) {
|
|
7648
|
+
const text3 = await response.text();
|
|
7649
|
+
throw new Error(`Reddit /api/v1/me fetch failed (${response.status}): ${text3}`);
|
|
6418
7650
|
}
|
|
6419
7651
|
const raw = await response.json();
|
|
6420
7652
|
const data = raw;
|
|
6421
|
-
if (!data.
|
|
6422
|
-
throw new Error("
|
|
7653
|
+
if (!data.id) {
|
|
7654
|
+
throw new Error("Reddit user response missing required field: id");
|
|
6423
7655
|
}
|
|
7656
|
+
if (!data.name) {
|
|
7657
|
+
throw new Error("Reddit user response missing required field: name");
|
|
7658
|
+
}
|
|
7659
|
+
const avatar = data.icon_img ? stripQueryParams(data.icon_img) : void 0;
|
|
6424
7660
|
return {
|
|
6425
|
-
id: data.
|
|
6426
|
-
email
|
|
7661
|
+
id: data.id,
|
|
7662
|
+
// No email — caller must handle the undefined case.
|
|
7663
|
+
email: void 0,
|
|
6427
7664
|
name: data.name,
|
|
6428
|
-
avatar
|
|
7665
|
+
avatar,
|
|
6429
7666
|
raw
|
|
6430
7667
|
};
|
|
6431
7668
|
}
|
|
6432
7669
|
return {
|
|
6433
|
-
id: "
|
|
6434
|
-
name: "
|
|
6435
|
-
authorizationUrl:
|
|
6436
|
-
tokenUrl:
|
|
6437
|
-
userInfoUrl:
|
|
7670
|
+
id: "reddit",
|
|
7671
|
+
name: "Reddit",
|
|
7672
|
+
authorizationUrl: AUTHORIZATION_URL12,
|
|
7673
|
+
tokenUrl: TOKEN_URL12,
|
|
7674
|
+
userInfoUrl: USER_INFO_URL9,
|
|
6438
7675
|
scopes,
|
|
6439
7676
|
getAuthorizationUrl,
|
|
6440
7677
|
exchangeCode,
|
|
6441
7678
|
getUserInfo
|
|
6442
7679
|
};
|
|
6443
7680
|
}
|
|
6444
|
-
function
|
|
7681
|
+
function normalizeProfile6(raw) {
|
|
7682
|
+
const data = raw;
|
|
7683
|
+
if (!data.id) {
|
|
7684
|
+
throw new Error("Reddit user response missing required field: id");
|
|
7685
|
+
}
|
|
7686
|
+
if (!data.name) {
|
|
7687
|
+
throw new Error("Reddit user response missing required field: name");
|
|
7688
|
+
}
|
|
7689
|
+
const avatar = data.icon_img ? stripQueryParams(data.icon_img) : void 0;
|
|
7690
|
+
return {
|
|
7691
|
+
id: data.id,
|
|
7692
|
+
// Reddit does not return email through OAuth; callers must handle this.
|
|
7693
|
+
email: void 0,
|
|
7694
|
+
name: data.name,
|
|
7695
|
+
avatar,
|
|
7696
|
+
raw
|
|
7697
|
+
};
|
|
7698
|
+
}
|
|
7699
|
+
function stripQueryParams(url) {
|
|
7700
|
+
try {
|
|
7701
|
+
const parsed = new URL(url);
|
|
7702
|
+
parsed.search = "";
|
|
7703
|
+
return parsed.toString();
|
|
7704
|
+
} catch {
|
|
7705
|
+
return url;
|
|
7706
|
+
}
|
|
7707
|
+
}
|
|
7708
|
+
function mergeScopes12(defaults, extras) {
|
|
6445
7709
|
if (!extras || extras.length === 0) return defaults;
|
|
6446
7710
|
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6447
7711
|
return [...merged];
|
|
6448
7712
|
}
|
|
6449
7713
|
|
|
6450
|
-
// src/auth/oauth/providers/
|
|
6451
|
-
var
|
|
6452
|
-
var
|
|
6453
|
-
var
|
|
6454
|
-
var
|
|
6455
|
-
|
|
6456
|
-
|
|
7714
|
+
// src/auth/oauth/providers/slack.ts
|
|
7715
|
+
var AUTHORIZATION_URL13 = "https://slack.com/oauth/v2/authorize";
|
|
7716
|
+
var TOKEN_URL13 = "https://slack.com/api/oauth.v2.access";
|
|
7717
|
+
var USER_INFO_URL10 = "https://slack.com/api/openid.connect.userInfo";
|
|
7718
|
+
var DEFAULT_SLACK_SCOPES = ["openid", "profile", "email"];
|
|
7719
|
+
var DEFAULT_SCOPES9 = DEFAULT_SLACK_SCOPES;
|
|
7720
|
+
function createSlackProvider(config) {
|
|
7721
|
+
const scopes = mergeScopes13(DEFAULT_SCOPES9, config.scopes);
|
|
6457
7722
|
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6458
7723
|
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6459
7724
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
6460
7725
|
const params = new URLSearchParams({
|
|
6461
|
-
response_type: "code",
|
|
6462
7726
|
client_id: config.clientId,
|
|
6463
7727
|
redirect_uri: effectiveRedirectUri,
|
|
7728
|
+
response_type: "code",
|
|
6464
7729
|
scope: scopes.join(" "),
|
|
6465
7730
|
state,
|
|
6466
7731
|
code_challenge: codeChallenge,
|
|
6467
7732
|
code_challenge_method: "S256"
|
|
6468
7733
|
});
|
|
6469
|
-
return `${
|
|
7734
|
+
return `${AUTHORIZATION_URL13}?${params.toString()}`;
|
|
6470
7735
|
}
|
|
6471
7736
|
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6472
7737
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6478,77 +7743,120 @@ function createLinkedInProvider(config) {
|
|
|
6478
7743
|
redirect_uri: effectiveRedirectUri,
|
|
6479
7744
|
code_verifier: codeVerifier
|
|
6480
7745
|
});
|
|
6481
|
-
const response = await fetch(
|
|
7746
|
+
const response = await fetch(TOKEN_URL13, {
|
|
6482
7747
|
method: "POST",
|
|
6483
7748
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6484
7749
|
body: body.toString()
|
|
6485
7750
|
});
|
|
6486
7751
|
if (!response.ok) {
|
|
6487
7752
|
const text3 = await response.text();
|
|
6488
|
-
throw new Error(`
|
|
7753
|
+
throw new Error(`Slack token exchange failed (${response.status}): ${text3}`);
|
|
6489
7754
|
}
|
|
6490
7755
|
const raw = await response.json();
|
|
6491
7756
|
const data = raw;
|
|
7757
|
+
if (!data.ok) {
|
|
7758
|
+
throw new Error(`Slack token exchange error: ${data.error ?? "unknown"}`);
|
|
7759
|
+
}
|
|
7760
|
+
const accessToken = data.authed_user?.access_token ?? data.access_token;
|
|
7761
|
+
if (!accessToken) {
|
|
7762
|
+
throw new Error("Slack token exchange returned no access_token");
|
|
7763
|
+
}
|
|
6492
7764
|
return {
|
|
6493
|
-
accessToken
|
|
6494
|
-
refreshToken:
|
|
6495
|
-
expiresIn:
|
|
6496
|
-
tokenType: data.token_type ?? "Bearer",
|
|
7765
|
+
accessToken,
|
|
7766
|
+
refreshToken: void 0,
|
|
7767
|
+
expiresIn: void 0,
|
|
7768
|
+
tokenType: data.authed_user?.token_type ?? data.token_type ?? "Bearer",
|
|
6497
7769
|
raw
|
|
6498
7770
|
};
|
|
6499
7771
|
}
|
|
6500
7772
|
async function getUserInfo(accessToken) {
|
|
6501
|
-
const response = await fetch(
|
|
7773
|
+
const response = await fetch(USER_INFO_URL10, {
|
|
6502
7774
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6503
7775
|
});
|
|
6504
7776
|
if (!response.ok) {
|
|
6505
7777
|
const text3 = await response.text();
|
|
6506
|
-
throw new Error(`
|
|
7778
|
+
throw new Error(`Slack openid.connect.userInfo fetch failed (${response.status}): ${text3}`);
|
|
6507
7779
|
}
|
|
6508
7780
|
const raw = await response.json();
|
|
6509
7781
|
const data = raw;
|
|
6510
|
-
if (!data.
|
|
6511
|
-
throw new Error(
|
|
7782
|
+
if (!data.ok) {
|
|
7783
|
+
throw new Error(`Slack userInfo error: ${data.error ?? "unknown"}`);
|
|
7784
|
+
}
|
|
7785
|
+
const id = data.sub ?? data["https://slack.com/user_id"];
|
|
7786
|
+
if (!id) {
|
|
7787
|
+
throw new Error("Slack userInfo response missing required field: sub");
|
|
6512
7788
|
}
|
|
6513
7789
|
if (!data.email) {
|
|
6514
|
-
throw new Error(
|
|
6515
|
-
"LinkedIn userinfo response has no email. Ensure the `email` and `openid` scopes are granted."
|
|
6516
|
-
);
|
|
7790
|
+
throw new Error("Slack userInfo response has no email. Ensure the `email` scope is granted.");
|
|
6517
7791
|
}
|
|
6518
|
-
const name = data.name ?? ([data.given_name, data.family_name].filter(Boolean).join(" ") || void 0);
|
|
6519
7792
|
return {
|
|
6520
|
-
id
|
|
7793
|
+
id,
|
|
6521
7794
|
email: data.email,
|
|
6522
|
-
name,
|
|
7795
|
+
name: data.name,
|
|
6523
7796
|
avatar: data.picture,
|
|
6524
7797
|
raw
|
|
6525
7798
|
};
|
|
6526
7799
|
}
|
|
6527
7800
|
return {
|
|
6528
|
-
id: "
|
|
6529
|
-
name: "
|
|
6530
|
-
authorizationUrl:
|
|
6531
|
-
tokenUrl:
|
|
6532
|
-
userInfoUrl:
|
|
7801
|
+
id: "slack",
|
|
7802
|
+
name: "Slack",
|
|
7803
|
+
authorizationUrl: AUTHORIZATION_URL13,
|
|
7804
|
+
tokenUrl: TOKEN_URL13,
|
|
7805
|
+
userInfoUrl: USER_INFO_URL10,
|
|
6533
7806
|
scopes,
|
|
6534
7807
|
getAuthorizationUrl,
|
|
6535
7808
|
exchangeCode,
|
|
6536
7809
|
getUserInfo
|
|
6537
7810
|
};
|
|
6538
7811
|
}
|
|
6539
|
-
function
|
|
7812
|
+
function normalizeProfile7(raw) {
|
|
7813
|
+
const data = raw;
|
|
7814
|
+
if (!data.ok) {
|
|
7815
|
+
throw new Error(`Slack userInfo error: ${data.error ?? "unknown"}`);
|
|
7816
|
+
}
|
|
7817
|
+
const id = data.sub ?? data["https://slack.com/user_id"];
|
|
7818
|
+
if (!id) {
|
|
7819
|
+
throw new Error("Slack userInfo response missing required field: sub");
|
|
7820
|
+
}
|
|
7821
|
+
if (!data.email) {
|
|
7822
|
+
throw new Error("Slack userInfo response has no email. Ensure the `email` scope is granted.");
|
|
7823
|
+
}
|
|
7824
|
+
return {
|
|
7825
|
+
id,
|
|
7826
|
+
email: data.email,
|
|
7827
|
+
name: data.name,
|
|
7828
|
+
avatar: data.picture,
|
|
7829
|
+
raw
|
|
7830
|
+
};
|
|
7831
|
+
}
|
|
7832
|
+
function mergeScopes13(defaults, extras) {
|
|
6540
7833
|
if (!extras || extras.length === 0) return defaults;
|
|
6541
7834
|
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6542
7835
|
return [...merged];
|
|
6543
7836
|
}
|
|
6544
7837
|
|
|
6545
|
-
// src/auth/oauth/providers/
|
|
6546
|
-
var
|
|
6547
|
-
var
|
|
6548
|
-
var
|
|
6549
|
-
var
|
|
6550
|
-
function
|
|
6551
|
-
const
|
|
7838
|
+
// src/auth/oauth/providers/spotify.ts
|
|
7839
|
+
var AUTHORIZATION_URL14 = "https://accounts.spotify.com/authorize";
|
|
7840
|
+
var TOKEN_URL14 = "https://accounts.spotify.com/api/token";
|
|
7841
|
+
var USER_INFO_URL11 = "https://api.spotify.com/v1/me";
|
|
7842
|
+
var DEFAULT_SPOTIFY_SCOPES = ["user-read-email", "user-read-private"];
|
|
7843
|
+
function normalizeProfile8(raw) {
|
|
7844
|
+
const data = raw;
|
|
7845
|
+
if (!data.id) {
|
|
7846
|
+
throw new Error("Spotify user response missing required field: id");
|
|
7847
|
+
}
|
|
7848
|
+
const avatar = Array.isArray(data.images) && data.images.length > 0 ? data.images[0]?.url : void 0;
|
|
7849
|
+
return {
|
|
7850
|
+
id: data.id,
|
|
7851
|
+
email: data.email,
|
|
7852
|
+
// emailVerified is not provided by Spotify
|
|
7853
|
+
name: data.display_name ?? void 0,
|
|
7854
|
+
avatar,
|
|
7855
|
+
raw
|
|
7856
|
+
};
|
|
7857
|
+
}
|
|
7858
|
+
function createSpotifyProvider(config) {
|
|
7859
|
+
const scopes = mergeScopes14(DEFAULT_SPOTIFY_SCOPES, config.scopes);
|
|
6552
7860
|
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6553
7861
|
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6554
7862
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6561,7 +7869,7 @@ function createMicrosoftProvider(config) {
|
|
|
6561
7869
|
code_challenge: codeChallenge,
|
|
6562
7870
|
code_challenge_method: "S256"
|
|
6563
7871
|
});
|
|
6564
|
-
return `${
|
|
7872
|
+
return `${AUTHORIZATION_URL14}?${params.toString()}`;
|
|
6565
7873
|
}
|
|
6566
7874
|
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6567
7875
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6573,14 +7881,14 @@ function createMicrosoftProvider(config) {
|
|
|
6573
7881
|
code_verifier: codeVerifier,
|
|
6574
7882
|
redirect_uri: effectiveRedirectUri
|
|
6575
7883
|
});
|
|
6576
|
-
const response = await fetch(
|
|
7884
|
+
const response = await fetch(TOKEN_URL14, {
|
|
6577
7885
|
method: "POST",
|
|
6578
7886
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6579
7887
|
body: body.toString()
|
|
6580
7888
|
});
|
|
6581
7889
|
if (!response.ok) {
|
|
6582
7890
|
const text3 = await response.text();
|
|
6583
|
-
throw new Error(`
|
|
7891
|
+
throw new Error(`Spotify token exchange failed (${response.status}): ${text3}`);
|
|
6584
7892
|
}
|
|
6585
7893
|
const raw = await response.json();
|
|
6586
7894
|
const data = raw;
|
|
@@ -6593,60 +7901,42 @@ function createMicrosoftProvider(config) {
|
|
|
6593
7901
|
};
|
|
6594
7902
|
}
|
|
6595
7903
|
async function getUserInfo(accessToken) {
|
|
6596
|
-
const response = await fetch(
|
|
7904
|
+
const response = await fetch(USER_INFO_URL11, {
|
|
6597
7905
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6598
7906
|
});
|
|
6599
7907
|
if (!response.ok) {
|
|
6600
7908
|
const text3 = await response.text();
|
|
6601
|
-
throw new Error(`
|
|
7909
|
+
throw new Error(`Spotify /v1/me fetch failed (${response.status}): ${text3}`);
|
|
6602
7910
|
}
|
|
6603
7911
|
const raw = await response.json();
|
|
6604
|
-
|
|
6605
|
-
if (!data.id) {
|
|
6606
|
-
throw new Error("Microsoft Graph /me response missing required field: id");
|
|
6607
|
-
}
|
|
6608
|
-
const email = data.mail ?? data.userPrincipalName;
|
|
6609
|
-
if (!email) {
|
|
6610
|
-
throw new Error(
|
|
6611
|
-
"Microsoft Graph /me response has no email or userPrincipalName. Ensure the `email` and `User.Read` scopes are granted."
|
|
6612
|
-
);
|
|
6613
|
-
}
|
|
6614
|
-
const name = data.displayName ?? ([data.givenName, data.surname].filter(Boolean).join(" ") || void 0);
|
|
6615
|
-
return {
|
|
6616
|
-
id: data.id,
|
|
6617
|
-
email,
|
|
6618
|
-
name,
|
|
6619
|
-
avatar: void 0,
|
|
6620
|
-
// Graph photo requires a separate /me/photo/$value call
|
|
6621
|
-
raw
|
|
6622
|
-
};
|
|
7912
|
+
return normalizeProfile8(raw);
|
|
6623
7913
|
}
|
|
6624
7914
|
return {
|
|
6625
|
-
id: "
|
|
6626
|
-
name: "
|
|
6627
|
-
authorizationUrl:
|
|
6628
|
-
tokenUrl:
|
|
6629
|
-
userInfoUrl:
|
|
7915
|
+
id: "spotify",
|
|
7916
|
+
name: "Spotify",
|
|
7917
|
+
authorizationUrl: AUTHORIZATION_URL14,
|
|
7918
|
+
tokenUrl: TOKEN_URL14,
|
|
7919
|
+
userInfoUrl: USER_INFO_URL11,
|
|
6630
7920
|
scopes,
|
|
6631
7921
|
getAuthorizationUrl,
|
|
6632
7922
|
exchangeCode,
|
|
6633
7923
|
getUserInfo
|
|
6634
7924
|
};
|
|
6635
7925
|
}
|
|
6636
|
-
function
|
|
7926
|
+
function mergeScopes14(defaults, extras) {
|
|
6637
7927
|
if (!extras || extras.length === 0) return defaults;
|
|
6638
7928
|
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6639
7929
|
return [...merged];
|
|
6640
7930
|
}
|
|
6641
7931
|
|
|
6642
|
-
// src/auth/oauth/providers/
|
|
6643
|
-
var
|
|
6644
|
-
var
|
|
6645
|
-
var
|
|
6646
|
-
var
|
|
6647
|
-
var
|
|
6648
|
-
function
|
|
6649
|
-
const scopes =
|
|
7932
|
+
// src/auth/oauth/providers/twitch.ts
|
|
7933
|
+
var AUTHORIZATION_URL15 = "https://id.twitch.tv/oauth2/authorize";
|
|
7934
|
+
var TOKEN_URL15 = "https://id.twitch.tv/oauth2/token";
|
|
7935
|
+
var USER_INFO_URL12 = "https://api.twitch.tv/helix/users";
|
|
7936
|
+
var DEFAULT_TWITCH_SCOPES = ["user:read:email"];
|
|
7937
|
+
var DEFAULT_SCOPES10 = DEFAULT_TWITCH_SCOPES;
|
|
7938
|
+
function createTwitchProvider(config) {
|
|
7939
|
+
const scopes = mergeScopes15(DEFAULT_SCOPES10, config.scopes);
|
|
6650
7940
|
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6651
7941
|
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6652
7942
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6659,7 +7949,7 @@ function createSlackProvider(config) {
|
|
|
6659
7949
|
code_challenge: codeChallenge,
|
|
6660
7950
|
code_challenge_method: "S256"
|
|
6661
7951
|
});
|
|
6662
|
-
return `${
|
|
7952
|
+
return `${AUTHORIZATION_URL15}?${params.toString()}`;
|
|
6663
7953
|
}
|
|
6664
7954
|
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6665
7955
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6668,89 +7958,103 @@ function createSlackProvider(config) {
|
|
|
6668
7958
|
client_id: config.clientId,
|
|
6669
7959
|
client_secret: config.clientSecret,
|
|
6670
7960
|
code: code2,
|
|
6671
|
-
|
|
6672
|
-
|
|
7961
|
+
code_verifier: codeVerifier,
|
|
7962
|
+
redirect_uri: effectiveRedirectUri
|
|
6673
7963
|
});
|
|
6674
|
-
const response = await fetch(
|
|
7964
|
+
const response = await fetch(TOKEN_URL15, {
|
|
6675
7965
|
method: "POST",
|
|
6676
7966
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6677
7967
|
body: body.toString()
|
|
6678
7968
|
});
|
|
6679
7969
|
if (!response.ok) {
|
|
6680
7970
|
const text3 = await response.text();
|
|
6681
|
-
throw new Error(`
|
|
7971
|
+
throw new Error(`Twitch token exchange failed (${response.status}): ${text3}`);
|
|
6682
7972
|
}
|
|
6683
7973
|
const raw = await response.json();
|
|
6684
7974
|
const data = raw;
|
|
6685
|
-
if (!data.ok) {
|
|
6686
|
-
throw new Error(`Slack token exchange error: ${data.error ?? "unknown"}`);
|
|
6687
|
-
}
|
|
6688
|
-
const accessToken = data.authed_user?.access_token ?? data.access_token;
|
|
6689
|
-
if (!accessToken) {
|
|
6690
|
-
throw new Error("Slack token exchange returned no access_token");
|
|
6691
|
-
}
|
|
6692
7975
|
return {
|
|
6693
|
-
accessToken,
|
|
6694
|
-
refreshToken:
|
|
6695
|
-
expiresIn:
|
|
6696
|
-
tokenType: data.
|
|
7976
|
+
accessToken: data.access_token,
|
|
7977
|
+
refreshToken: data.refresh_token,
|
|
7978
|
+
expiresIn: data.expires_in,
|
|
7979
|
+
tokenType: data.token_type ?? "Bearer",
|
|
6697
7980
|
raw
|
|
6698
7981
|
};
|
|
6699
7982
|
}
|
|
6700
7983
|
async function getUserInfo(accessToken) {
|
|
6701
|
-
const response = await fetch(
|
|
6702
|
-
headers: {
|
|
7984
|
+
const response = await fetch(USER_INFO_URL12, {
|
|
7985
|
+
headers: {
|
|
7986
|
+
Authorization: `Bearer ${accessToken}`,
|
|
7987
|
+
"Client-ID": config.clientId
|
|
7988
|
+
}
|
|
6703
7989
|
});
|
|
6704
7990
|
if (!response.ok) {
|
|
6705
7991
|
const text3 = await response.text();
|
|
6706
|
-
throw new Error(`
|
|
7992
|
+
throw new Error(`Twitch /helix/users fetch failed (${response.status}): ${text3}`);
|
|
6707
7993
|
}
|
|
6708
7994
|
const raw = await response.json();
|
|
6709
|
-
const
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
const id = data.sub ?? data["https://slack.com/user_id"];
|
|
6714
|
-
if (!id) {
|
|
6715
|
-
throw new Error("Slack userInfo response missing required field: sub");
|
|
7995
|
+
const body = raw;
|
|
7996
|
+
const user = body.data?.[0];
|
|
7997
|
+
if (!user?.id) {
|
|
7998
|
+
throw new Error("Twitch user response missing required field: id");
|
|
6716
7999
|
}
|
|
6717
|
-
if (!
|
|
6718
|
-
throw new Error(
|
|
8000
|
+
if (!user.email) {
|
|
8001
|
+
throw new Error(
|
|
8002
|
+
"Twitch user response has no email. Ensure the `user:read:email` scope is granted."
|
|
8003
|
+
);
|
|
6719
8004
|
}
|
|
6720
8005
|
return {
|
|
6721
|
-
id,
|
|
6722
|
-
email:
|
|
6723
|
-
name:
|
|
6724
|
-
avatar:
|
|
8006
|
+
id: user.id,
|
|
8007
|
+
email: user.email,
|
|
8008
|
+
name: user.display_name,
|
|
8009
|
+
avatar: user.profile_image_url,
|
|
6725
8010
|
raw
|
|
6726
8011
|
};
|
|
6727
8012
|
}
|
|
6728
8013
|
return {
|
|
6729
|
-
id: "
|
|
6730
|
-
name: "
|
|
6731
|
-
authorizationUrl:
|
|
6732
|
-
tokenUrl:
|
|
6733
|
-
userInfoUrl:
|
|
8014
|
+
id: "twitch",
|
|
8015
|
+
name: "Twitch",
|
|
8016
|
+
authorizationUrl: AUTHORIZATION_URL15,
|
|
8017
|
+
tokenUrl: TOKEN_URL15,
|
|
8018
|
+
userInfoUrl: USER_INFO_URL12,
|
|
6734
8019
|
scopes,
|
|
6735
8020
|
getAuthorizationUrl,
|
|
6736
8021
|
exchangeCode,
|
|
6737
8022
|
getUserInfo
|
|
6738
8023
|
};
|
|
6739
8024
|
}
|
|
6740
|
-
function
|
|
8025
|
+
function normalizeProfile9(raw) {
|
|
8026
|
+
const body = raw;
|
|
8027
|
+
const user = body.data?.[0];
|
|
8028
|
+
if (!user?.id) {
|
|
8029
|
+
throw new Error("Twitch user response missing required field: id");
|
|
8030
|
+
}
|
|
8031
|
+
if (!user.email) {
|
|
8032
|
+
throw new Error(
|
|
8033
|
+
"Twitch user response has no email. Ensure the `user:read:email` scope is granted."
|
|
8034
|
+
);
|
|
8035
|
+
}
|
|
8036
|
+
return {
|
|
8037
|
+
id: user.id,
|
|
8038
|
+
email: user.email,
|
|
8039
|
+
name: user.display_name,
|
|
8040
|
+
avatar: user.profile_image_url,
|
|
8041
|
+
raw
|
|
8042
|
+
};
|
|
8043
|
+
}
|
|
8044
|
+
function mergeScopes15(defaults, extras) {
|
|
6741
8045
|
if (!extras || extras.length === 0) return defaults;
|
|
6742
8046
|
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6743
8047
|
return [...merged];
|
|
6744
8048
|
}
|
|
6745
8049
|
|
|
6746
8050
|
// src/auth/oauth/providers/twitter.ts
|
|
6747
|
-
var
|
|
6748
|
-
var
|
|
6749
|
-
var
|
|
8051
|
+
var AUTHORIZATION_URL16 = "https://twitter.com/i/oauth2/authorize";
|
|
8052
|
+
var TOKEN_URL16 = "https://api.twitter.com/2/oauth2/token";
|
|
8053
|
+
var USER_INFO_URL13 = "https://api.twitter.com/2/users/me";
|
|
6750
8054
|
var USER_FIELDS = "id,name,username,profile_image_url";
|
|
6751
|
-
var
|
|
8055
|
+
var DEFAULT_SCOPES11 = ["users.read", "tweet.read"];
|
|
6752
8056
|
function createTwitterProvider(config) {
|
|
6753
|
-
const scopes =
|
|
8057
|
+
const scopes = mergeScopes16(DEFAULT_SCOPES11, config.scopes);
|
|
6754
8058
|
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
6755
8059
|
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
6756
8060
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6763,7 +8067,7 @@ function createTwitterProvider(config) {
|
|
|
6763
8067
|
code_challenge: codeChallenge,
|
|
6764
8068
|
code_challenge_method: "S256"
|
|
6765
8069
|
});
|
|
6766
|
-
return `${
|
|
8070
|
+
return `${AUTHORIZATION_URL16}?${params.toString()}`;
|
|
6767
8071
|
}
|
|
6768
8072
|
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
6769
8073
|
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
@@ -6774,7 +8078,7 @@ function createTwitterProvider(config) {
|
|
|
6774
8078
|
redirect_uri: effectiveRedirectUri
|
|
6775
8079
|
});
|
|
6776
8080
|
const credentials = btoa(`${config.clientId}:${config.clientSecret}`);
|
|
6777
|
-
const response = await fetch(
|
|
8081
|
+
const response = await fetch(TOKEN_URL16, {
|
|
6778
8082
|
method: "POST",
|
|
6779
8083
|
headers: {
|
|
6780
8084
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -6797,7 +8101,7 @@ function createTwitterProvider(config) {
|
|
|
6797
8101
|
};
|
|
6798
8102
|
}
|
|
6799
8103
|
async function getUserInfo(accessToken) {
|
|
6800
|
-
const url = `${
|
|
8104
|
+
const url = `${USER_INFO_URL13}?user.fields=${USER_FIELDS}`;
|
|
6801
8105
|
const response = await fetch(url, {
|
|
6802
8106
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
6803
8107
|
});
|
|
@@ -6829,16 +8133,113 @@ function createTwitterProvider(config) {
|
|
|
6829
8133
|
return {
|
|
6830
8134
|
id: "twitter",
|
|
6831
8135
|
name: "Twitter",
|
|
6832
|
-
authorizationUrl:
|
|
6833
|
-
tokenUrl:
|
|
6834
|
-
userInfoUrl:
|
|
8136
|
+
authorizationUrl: AUTHORIZATION_URL16,
|
|
8137
|
+
tokenUrl: TOKEN_URL16,
|
|
8138
|
+
userInfoUrl: USER_INFO_URL13,
|
|
6835
8139
|
scopes,
|
|
6836
8140
|
getAuthorizationUrl,
|
|
6837
8141
|
exchangeCode,
|
|
6838
8142
|
getUserInfo
|
|
6839
8143
|
};
|
|
6840
8144
|
}
|
|
6841
|
-
function
|
|
8145
|
+
function mergeScopes16(defaults, extras) {
|
|
8146
|
+
if (!extras || extras.length === 0) return defaults;
|
|
8147
|
+
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
8148
|
+
return [...merged];
|
|
8149
|
+
}
|
|
8150
|
+
|
|
8151
|
+
// src/auth/oauth/providers/zoom.ts
|
|
8152
|
+
var AUTHORIZATION_URL17 = "https://zoom.us/oauth/authorize";
|
|
8153
|
+
var TOKEN_URL17 = "https://zoom.us/oauth/token";
|
|
8154
|
+
var USER_INFO_URL14 = "https://api.zoom.us/v2/users/me";
|
|
8155
|
+
var DEFAULT_ZOOM_SCOPES = ["user:read"];
|
|
8156
|
+
function normalizeProfile10(raw) {
|
|
8157
|
+
const data = raw;
|
|
8158
|
+
if (!data.id) {
|
|
8159
|
+
throw new Error("Zoom user response missing required field: id");
|
|
8160
|
+
}
|
|
8161
|
+
if (!data.email) {
|
|
8162
|
+
throw new Error("Zoom user response missing required field: email");
|
|
8163
|
+
}
|
|
8164
|
+
const joinedName = [data.first_name, data.last_name].filter(Boolean).join(" ");
|
|
8165
|
+
const name = data.display_name ?? (joinedName.length > 0 ? joinedName : void 0);
|
|
8166
|
+
return {
|
|
8167
|
+
id: data.id,
|
|
8168
|
+
email: data.email,
|
|
8169
|
+
name,
|
|
8170
|
+
avatar: data.pic_url,
|
|
8171
|
+
raw
|
|
8172
|
+
};
|
|
8173
|
+
}
|
|
8174
|
+
function createZoomProvider(config) {
|
|
8175
|
+
const scopes = mergeScopes17(DEFAULT_ZOOM_SCOPES, config.scopes);
|
|
8176
|
+
async function getAuthorizationUrl(state, codeVerifier, redirectUri) {
|
|
8177
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
8178
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
8179
|
+
const params = new URLSearchParams({
|
|
8180
|
+
client_id: config.clientId,
|
|
8181
|
+
redirect_uri: effectiveRedirectUri,
|
|
8182
|
+
response_type: "code",
|
|
8183
|
+
scope: scopes.join(" "),
|
|
8184
|
+
state,
|
|
8185
|
+
code_challenge: codeChallenge,
|
|
8186
|
+
code_challenge_method: "S256"
|
|
8187
|
+
});
|
|
8188
|
+
return `${AUTHORIZATION_URL17}?${params.toString()}`;
|
|
8189
|
+
}
|
|
8190
|
+
async function exchangeCode(code2, codeVerifier, redirectUri) {
|
|
8191
|
+
const effectiveRedirectUri = config.redirectUri ?? redirectUri;
|
|
8192
|
+
const body = new URLSearchParams({
|
|
8193
|
+
grant_type: "authorization_code",
|
|
8194
|
+
client_id: config.clientId,
|
|
8195
|
+
client_secret: config.clientSecret,
|
|
8196
|
+
code: code2,
|
|
8197
|
+
code_verifier: codeVerifier,
|
|
8198
|
+
redirect_uri: effectiveRedirectUri
|
|
8199
|
+
});
|
|
8200
|
+
const response = await fetch(TOKEN_URL17, {
|
|
8201
|
+
method: "POST",
|
|
8202
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
8203
|
+
body: body.toString()
|
|
8204
|
+
});
|
|
8205
|
+
if (!response.ok) {
|
|
8206
|
+
const text3 = await response.text();
|
|
8207
|
+
throw new Error(`Zoom token exchange failed (${response.status}): ${text3}`);
|
|
8208
|
+
}
|
|
8209
|
+
const raw = await response.json();
|
|
8210
|
+
const data = raw;
|
|
8211
|
+
return {
|
|
8212
|
+
accessToken: data.access_token,
|
|
8213
|
+
refreshToken: data.refresh_token,
|
|
8214
|
+
expiresIn: data.expires_in,
|
|
8215
|
+
tokenType: data.token_type ?? "Bearer",
|
|
8216
|
+
raw
|
|
8217
|
+
};
|
|
8218
|
+
}
|
|
8219
|
+
async function getUserInfo(accessToken) {
|
|
8220
|
+
const response = await fetch(USER_INFO_URL14, {
|
|
8221
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
8222
|
+
});
|
|
8223
|
+
if (!response.ok) {
|
|
8224
|
+
const text3 = await response.text();
|
|
8225
|
+
throw new Error(`Zoom /v2/users/me fetch failed (${response.status}): ${text3}`);
|
|
8226
|
+
}
|
|
8227
|
+
const raw = await response.json();
|
|
8228
|
+
return normalizeProfile10(raw);
|
|
8229
|
+
}
|
|
8230
|
+
return {
|
|
8231
|
+
id: "zoom",
|
|
8232
|
+
name: "Zoom",
|
|
8233
|
+
authorizationUrl: AUTHORIZATION_URL17,
|
|
8234
|
+
tokenUrl: TOKEN_URL17,
|
|
8235
|
+
userInfoUrl: USER_INFO_URL14,
|
|
8236
|
+
scopes,
|
|
8237
|
+
getAuthorizationUrl,
|
|
8238
|
+
exchangeCode,
|
|
8239
|
+
getUserInfo
|
|
8240
|
+
};
|
|
8241
|
+
}
|
|
8242
|
+
function mergeScopes17(defaults, extras) {
|
|
6842
8243
|
if (!extras || extras.length === 0) return defaults;
|
|
6843
8244
|
const merged = /* @__PURE__ */ new Set([...defaults, ...extras]);
|
|
6844
8245
|
return [...merged];
|
|
@@ -7113,7 +8514,7 @@ var DEFAULT_REFRESH_TOKEN_TTL = 86400 * 30;
|
|
|
7113
8514
|
var DEFAULT_AUTH_CODE_TTL = 600;
|
|
7114
8515
|
var DEFAULT_ID_TOKEN_TTL = 3600;
|
|
7115
8516
|
var DEFAULT_SIGNING_ALG = "RS256";
|
|
7116
|
-
var
|
|
8517
|
+
var DEFAULT_SCOPES12 = ["openid", "profile", "email"];
|
|
7117
8518
|
var CLIENT_ID_BYTE_LENGTH = 16;
|
|
7118
8519
|
var CLIENT_SECRET_BYTE_LENGTH = 32;
|
|
7119
8520
|
var AUTH_CODE_BYTE_LENGTH = 32;
|
|
@@ -7140,7 +8541,7 @@ function createOidcProviderModule(config, db, getUserClaims) {
|
|
|
7140
8541
|
const refreshTokenTtl = config.refreshTokenTtl ?? DEFAULT_REFRESH_TOKEN_TTL;
|
|
7141
8542
|
const authCodeTtl = config.authCodeTtl ?? DEFAULT_AUTH_CODE_TTL;
|
|
7142
8543
|
const idTokenTtl = config.idTokenTtl ?? DEFAULT_ID_TOKEN_TTL;
|
|
7143
|
-
const supportedScopes = config.supportedScopes ??
|
|
8544
|
+
const supportedScopes = config.supportedScopes ?? DEFAULT_SCOPES12;
|
|
7144
8545
|
let signingKeyPromise;
|
|
7145
8546
|
let publicJwkPromise;
|
|
7146
8547
|
async function getSigningKey() {
|
|
@@ -21754,6 +23155,6 @@ async function verifyWebhookSignature3(secret, rawBody, signature) {
|
|
|
21754
23155
|
return diff === 0;
|
|
21755
23156
|
}
|
|
21756
23157
|
|
|
21757
|
-
export { CredentialStatusSchema, CredentialSubjectSchema, EVENT_TYPES, HibpApiError, HibpBreachedError, KAVACHOS_AUDIT_CONTEXT, KAVACHOS_AUDIT_CREDENTIAL, KAVACH_AGENT_CREDENTIAL, KAVACH_DELEGATION_CREDENTIAL, KAVACH_PERMISSION_CREDENTIAL, KVStore, MemoryStore, MultiSessionLimitError, OAuthProxyError, OneTapVerifyError, ProofSchema, RefreshTokenError, SSO_ERROR, SsoError, VC_CONTEXT_V1, VC_CONTEXT_V2, VC_TYPE_CREDENTIAL, VC_TYPE_PRESENTATION, VerifiableCredentialSchema, VerifiablePresentationSchema, additionalFields, admin, agentCards, agentDids, agents, anonymousAuth, apiKeys2 as apiKeys, apiKeys as apiKeysTable, approvalRequests, auditLogs, bearerAuth, budgetPolicies, buildDidDocument, buildSessionMetadata, classifyViolation, constantTimeEqual, createAdditionalFieldsModule, createAdminModule, createAgentModule, createAnonymousAuthModule, createApiKeyManagerModule, createAppleProvider, createApprovalModule, createAuditModule, createCaptchaModule, createCookieSessionManager, createCostAttributionModule, createCustomSessionModule, createDatabase, createDatabaseSync, createDelegationModule, createDeviceAuthModule, createDidModule, createDiscordProvider, createEmailOtpModule, createEmailTemplates, createEmailVerificationModule, createEphemeralSessionModule, createEventStreamModule, createFederationModule, createGdprModule, createGithubProvider, createGitlabProvider, createGoogleProvider, createHibpModule, createI18n, createJwtSessionModule, createKavach, createLastLoginModule, createLinkedInProvider, createMagicLinkModule, createMicrosoftProvider, createMultiSessionModule, createOAuthModule, createOAuthProxyModule, createOidcProviderModule, createOneTapModule, createOneTimeTokenModule, createOpenApiModule, createOrgModule, createPasskeyModule, createPasswordResetModule, createPermissionEngine, createPhoneAuthModule, createPluginRouter, createPolarModule, createPolicyModule, createPresentation, createPrivilegeAnalyzer, createRateLimiter, createReBACModule, createRedirectChain, createScimModule, createSessionFreshnessModule, createSessionManager, createSessionRefresher, createSiweModule, createSlackProvider, createSsoModule, createStripeModule, createTables, createTenantModule, createTokenFamilyStore, createTotpModule, createTrustModule, createTrustedDeviceModule, createTwitterProvider, createUsernameAuthModule, createVCIssuer, createVCVerifier, createWebhookModule2 as createWebhookModule, customAuth, customSession, de, delegationChains, deviceAuth, deviceLabelFromRequest, emailOtp, emailOtps, en, es, exportAuditAsVC, fr, fromBase64Url, fromHex, gdpr, generateCsrfToken, generateDidKey, generateDidWeb, generateId, generateOpenAPISpec, getCookie2 as getCookie, getDidWebUrl, getPermissionTemplate, headerAuth, hmacSha1Raw, hmacSha256, hmacSha256Raw, importHmacKey, initializePlugins, ja, kvStore, listAuditRecords, magicLink, magicLinks, mcpServers, oauth, oauthAccessTokens, oauthAuthorizationCodes, oauthClients, oauthProxy, oneTap, orgInvitations, orgMembers, orgRoles, organization, organizations, parseCookies2 as parseCookies, parseCookiesFromRequest, passkey, passkeyChallenges, passkeyCredentials, pbkdf2Hash, pbkdf2Verify, permissionTemplates, permissions, polar, randomBytes, randomBytesHex, rateLimit, rateLimits, resolveDidKey, resolveDidWeb, scim, serializeCookie, serializeCookieDeletion, sessions, sha1, sha256, sha256Raw, signPayload2 as signPayload, siwe, ssoConnections, stripe, tenants, toBase64Url, toHex, totpRecords, trustScores, twoFactor, users, validateCsrfToken, validateOrigin, verifyPayload, verifyPresentation, verifyWebhookSignature3 as verifyWebhookSignature, withRateLimit, zh };
|
|
23158
|
+
export { CredentialStatusSchema, CredentialSubjectSchema, DEFAULT_ATLASSIAN_SCOPES, DEFAULT_DISCORD_SCOPES, DEFAULT_DROPBOX_SCOPES, DEFAULT_FIGMA_SCOPES, DEFAULT_NOTION_SCOPES, DEFAULT_REDDIT_SCOPES, DEFAULT_SLACK_SCOPES, DEFAULT_SPOTIFY_SCOPES, DEFAULT_TWITCH_SCOPES, DEFAULT_ZOOM_SCOPES, EVENT_TYPES, HibpApiError, HibpBreachedError, KAVACHOS_AUDIT_CONTEXT, KAVACHOS_AUDIT_CREDENTIAL, KAVACH_AGENT_CREDENTIAL, KAVACH_DELEGATION_CREDENTIAL, KAVACH_PERMISSION_CREDENTIAL, KVStore, MemoryStore, MultiSessionLimitError, OAuthProxyError, OneTapVerifyError, ProofSchema, RefreshTokenError, SSO_ERROR, SsoError, VC_CONTEXT_V1, VC_CONTEXT_V2, VC_TYPE_CREDENTIAL, VC_TYPE_PRESENTATION, VerifiableCredentialSchema, VerifiablePresentationSchema, additionalFields, admin, agentCards, agentDids, agents, anonymousAuth, apiKeys2 as apiKeys, apiKeys as apiKeysTable, approvalRequests, atlassianProvider, auditLogs, auth0Provider, bearerAuth, bitbucketProvider, budgetPolicies, buildDidDocument, buildSessionMetadata, classifyViolation, cognitoProvider, coinbaseProvider, constantTimeEqual, createAdditionalFieldsModule, createAdminModule, createAgentModule, createAnonymousAuthModule, createApiKeyManagerModule, createAppleProvider, createApprovalModule, createAtlassianProvider, createAuditModule, createCaptchaModule, createCookieSessionManager, createCostAttributionModule, createCustomSessionModule, createDatabase, createDatabaseSync, createDelegationModule, createDeviceAuthModule, createDidModule, createDiscordProvider, createDropboxProvider, createEmailOtpModule, createEmailTemplates, createEmailVerificationModule, createEphemeralSessionModule, createEventStreamModule, createFederationModule, createFigmaProvider, createGdprModule, createGithubProvider, createGitlabProvider, createGoogleProvider, createHibpModule, createI18n, createJwtSessionModule, createKavach, createLastLoginModule, createLinkedInProvider, createMagicLinkModule, createMicrosoftProvider, createMultiSessionModule, createNotionProvider, createOAuthModule, createOAuthProxyModule, createOidcProviderModule, createOneTapModule, createOneTimeTokenModule, createOpenApiModule, createOrgModule, createPasskeyModule, createPasswordResetModule, createPermissionEngine, createPhoneAuthModule, createPluginRouter, createPolarModule, createPolicyModule, createPresentation, createPrivilegeAnalyzer, createRateLimiter, createReBACModule, createRedditProvider, createRedirectChain, createScimModule, createSessionFreshnessModule, createSessionManager, createSessionRefresher, createSiweModule, createSlackProvider, createSpotifyProvider, createSsoModule, createStripeModule, createTables, createTenantModule, createTokenFamilyStore, createTotpModule, createTrustModule, createTrustedDeviceModule, createTwitchProvider, createTwitterProvider, createUsernameAuthModule, createVCIssuer, createVCVerifier, createWebhookModule2 as createWebhookModule, createZoomProvider, customAuth, customSession, de, delegationChains, deviceAuth, deviceLabelFromRequest, dropboxProvider, emailOtp, emailOtps, en, es, exportAuditAsVC, facebookProvider, figmaProvider, fr, fromBase64Url, fromHex, gdpr, generateCsrfToken, generateDidKey, generateDidWeb, generateId, generateOpenAPISpec, genericOIDC, getCookie2 as getCookie, getDidWebUrl, getPermissionTemplate, headerAuth, hmacSha1Raw, hmacSha256, hmacSha256Raw, huggingfaceProvider, importHmacKey, initializePlugins, ja, kakaoProvider, kickProvider, kvStore, lineProvider, linearProvider, listAuditRecords, magicLink, magicLinks, mcpServers, naverProvider, normalizeProfile as normalizeAtlassianProfile, normalizeProfile2 as normalizeDiscordProfile, normalizeProfile3 as normalizeDropboxProfile, normalizeProfile4 as normalizeFigmaProfile, normalizeProfile5 as normalizeNotionProfile, normalizeProfile6 as normalizeRedditProfile, normalizeProfile7 as normalizeSlackProfile, normalizeProfile8 as normalizeSpotifyProfile, normalizeProfile9 as normalizeTwitchProfile, normalizeProfile10 as normalizeZoomProfile, notionProvider, oauth, oauthAccessTokens, oauthAuthorizationCodes, oauthClients, oauthProxy, oktaProvider, oneTap, orgInvitations, orgMembers, orgRoles, organization, organizations, parseCookies2 as parseCookies, parseCookiesFromRequest, passkey, passkeyChallenges, passkeyCredentials, paypalProvider, pbkdf2Hash, pbkdf2Verify, permissionTemplates, permissions, polar, polarProvider, railwayProvider, randomBytes, randomBytesHex, rateLimit, rateLimits, redditProvider, resolveDidKey, resolveDidWeb, robloxProvider, salesforceProvider, scim, serializeCookie, serializeCookieDeletion, sessions, sha1, sha256, sha256Raw, signPayload2 as signPayload, siwe, spotifyProvider, ssoConnections, stripe, tenants, tiktokProvider, toBase64Url, toHex, totpRecords, trustScores, twitchProvider, twoFactor, users, validateCsrfToken, validateOrigin, vercelProvider, verifyPayload, verifyPresentation, verifyWebhookSignature3 as verifyWebhookSignature, vkProvider, wechatProvider, withRateLimit, yahooProvider, zh, zoomProvider };
|
|
21758
23159
|
//# sourceMappingURL=index.js.map
|
|
21759
23160
|
//# sourceMappingURL=index.js.map
|