@absolutejs/auth 0.55.7 → 0.55.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/dist/abuse/captcha.d.ts +11 -0
  2. package/dist/abuse/config.d.ts +29 -0
  3. package/dist/actions.d.ts +27 -0
  4. package/dist/adaptive/config.d.ts +34 -0
  5. package/dist/adaptive/fingerprint.d.ts +2 -0
  6. package/dist/adaptive/inMemoryStores.d.ts +3 -0
  7. package/dist/adaptive/postgresStores.d.ts +245 -0
  8. package/dist/adaptive/types.d.ts +62 -0
  9. package/dist/agents/config.d.ts +44 -0
  10. package/dist/agents/context.d.ts +46 -0
  11. package/dist/agents/idJag.d.ts +49 -0
  12. package/dist/agents/inMemoryStores.d.ts +4 -0
  13. package/dist/agents/oidcAdapter.d.ts +12 -0
  14. package/dist/agents/postgresStores.d.ts +569 -0
  15. package/dist/agents/principal.d.ts +4 -0
  16. package/dist/agents/registration.d.ts +162 -0
  17. package/dist/agents/registrationClient.d.ts +50 -0
  18. package/dist/agents/routes.d.ts +321 -0
  19. package/dist/agents/types.d.ts +129 -0
  20. package/dist/apikeys/config.d.ts +64 -0
  21. package/dist/apikeys/inMemoryStores.d.ts +4 -0
  22. package/dist/apikeys/postgresStores.d.ts +359 -0
  23. package/dist/apikeys/routes.d.ts +83 -0
  24. package/dist/apikeys/types.d.ts +53 -0
  25. package/dist/audit/config.d.ts +9 -0
  26. package/dist/audit/export.d.ts +2 -0
  27. package/dist/audit/inMemoryAuditStore.d.ts +2 -0
  28. package/dist/audit/integrity.d.ts +19 -0
  29. package/dist/audit/postgresAuditStore.d.ts +116 -0
  30. package/dist/audit/siem.d.ts +11 -0
  31. package/dist/audit/types.d.ts +19 -0
  32. package/dist/audit/wrap.d.ts +9 -0
  33. package/dist/authContext.d.ts +193 -0
  34. package/dist/authorization/config.d.ts +19 -0
  35. package/dist/authorization/protectPermission.d.ts +52 -0
  36. package/dist/compliance/cipher.d.ts +5 -0
  37. package/dist/compliance/config.d.ts +18 -0
  38. package/dist/compliance/redaction.d.ts +8 -0
  39. package/dist/compliance/routes.d.ts +89 -0
  40. package/dist/constants.d.ts +10 -0
  41. package/dist/credentials/backgroundOps.d.ts +45 -0
  42. package/dist/credentials/config.d.ts +68 -0
  43. package/dist/credentials/emailValidation.d.ts +9 -0
  44. package/dist/credentials/emailVerification.d.ts +83 -0
  45. package/dist/credentials/import.d.ts +34 -0
  46. package/dist/credentials/inMemoryCredentialStore.d.ts +2 -0
  47. package/dist/credentials/legacyHashers.d.ts +3 -0
  48. package/dist/credentials/login.d.ts +76 -0
  49. package/dist/credentials/passwordPolicy.d.ts +15 -0
  50. package/dist/credentials/passwordReset.d.ts +87 -0
  51. package/dist/credentials/postgresCredentialStore.d.ts +235 -0
  52. package/dist/credentials/register.d.ts +54 -0
  53. package/dist/credentials/routes.d.ts +201 -0
  54. package/dist/credentials/types.d.ts +26 -0
  55. package/dist/crypto.d.ts +32 -0
  56. package/dist/errors.d.ts +12 -0
  57. package/dist/federation/tokenStore.d.ts +29 -0
  58. package/dist/fga/config.d.ts +53 -0
  59. package/dist/fga/inMemoryStores.d.ts +3 -0
  60. package/dist/fga/postgresStores.d.ts +116 -0
  61. package/dist/fga/redisCheckCache.d.ts +11 -0
  62. package/dist/fga/schema.d.ts +2 -0
  63. package/dist/fga/types.d.ts +28 -0
  64. package/dist/htmx/configuredRoutes.d.ts +542 -0
  65. package/dist/htmx/renderers.d.ts +8 -0
  66. package/dist/htmx/routes.d.ts +514 -0
  67. package/dist/htmx/types.d.ts +129 -0
  68. package/dist/linkedProviders/inMemoryStores.d.ts +9 -0
  69. package/dist/linkedProviders/index.d.ts +3 -0
  70. package/dist/linkedProviders/index.js +3233 -0
  71. package/dist/linkedProviders/index.js.map +14 -0
  72. package/dist/linkedProviders/neonStores.d.ts +484 -0
  73. package/dist/linkedProviders/oauthAccountResolver.d.ts +28 -0
  74. package/dist/linkedProviders/oauthResolver.d.ts +9 -0
  75. package/dist/linkedProviders/resolver.d.ts +22 -0
  76. package/dist/lockout/config.d.ts +17 -0
  77. package/dist/lockout/inMemoryLockoutStore.d.ts +2 -0
  78. package/dist/lockout/postgresLockoutStore.d.ts +71 -0
  79. package/dist/lockout/redisLockoutStore.d.ts +3 -0
  80. package/dist/lockout/types.d.ts +12 -0
  81. package/dist/mfa/backupCodes.d.ts +5 -0
  82. package/dist/mfa/challenge.d.ts +70 -0
  83. package/dist/mfa/config.d.ts +50 -0
  84. package/dist/mfa/gate.d.ts +2 -0
  85. package/dist/mfa/inMemoryMfaStore.d.ts +2 -0
  86. package/dist/mfa/management.d.ts +106 -0
  87. package/dist/mfa/postgresMfaStore.d.ts +206 -0
  88. package/dist/mfa/rotation.d.ts +17 -0
  89. package/dist/mfa/routes.d.ts +234 -0
  90. package/dist/mfa/secret.d.ts +2 -0
  91. package/dist/mfa/sms.d.ts +105 -0
  92. package/dist/mfa/totp.d.ts +91 -0
  93. package/dist/mfa/types.d.ts +23 -0
  94. package/dist/migrations/generate.d.ts +2 -0
  95. package/dist/migrations/index.d.ts +5 -0
  96. package/dist/migrations/runner.d.ts +13 -0
  97. package/dist/migrations/types.d.ts +14 -0
  98. package/dist/oidc/clientAuth.d.ts +19 -0
  99. package/dist/oidc/clientIdMetadata.d.ts +32 -0
  100. package/dist/oidc/config.d.ts +295 -0
  101. package/dist/oidc/dpop.d.ts +23 -0
  102. package/dist/oidc/inMemoryStores.d.ts +11 -0
  103. package/dist/oidc/inMemoryVciStores.d.ts +3 -0
  104. package/dist/oidc/jar.d.ts +14 -0
  105. package/dist/oidc/keys.d.ts +25 -0
  106. package/dist/oidc/logout.d.ts +38 -0
  107. package/dist/oidc/mtls.d.ts +11 -0
  108. package/dist/oidc/par.d.ts +28 -0
  109. package/dist/oidc/postgresStores.d.ts +1187 -0
  110. package/dist/oidc/registration.d.ts +138 -0
  111. package/dist/oidc/routes.d.ts +568 -0
  112. package/dist/oidc/types.d.ts +143 -0
  113. package/dist/oidc/userinfo.d.ts +21 -0
  114. package/dist/oidc/vci.d.ts +159 -0
  115. package/dist/oidc/vciRoutes.d.ts +92 -0
  116. package/dist/organizations/config.d.ts +46 -0
  117. package/dist/organizations/inMemoryOrganizationStore.d.ts +2 -0
  118. package/dist/organizations/operations.d.ts +39 -0
  119. package/dist/organizations/postgresOrganizationStore.d.ts +340 -0
  120. package/dist/organizations/routes.d.ts +299 -0
  121. package/dist/organizations/types.d.ts +45 -0
  122. package/dist/passwordless/config.d.ts +43 -0
  123. package/dist/passwordless/inMemoryPasswordlessTokenStore.d.ts +2 -0
  124. package/dist/passwordless/postgresPasswordlessTokenStore.d.ts +56 -0
  125. package/dist/passwordless/routes.d.ts +163 -0
  126. package/dist/passwordless/types.d.ts +9 -0
  127. package/dist/pluginIdentity.d.ts +2 -0
  128. package/dist/portal/config.d.ts +34 -0
  129. package/dist/portal/inMemorySetupSessionStore.d.ts +2 -0
  130. package/dist/portal/operations.d.ts +10 -0
  131. package/dist/portal/postgresSetupSessionStore.d.ts +116 -0
  132. package/dist/portal/routes.d.ts +160 -0
  133. package/dist/portal/types.d.ts +16 -0
  134. package/dist/providers/clients.d.ts +1818 -0
  135. package/dist/providersFromEnv.d.ts +19 -0
  136. package/dist/roles/config.d.ts +27 -0
  137. package/dist/roles/inMemoryRoleStore.d.ts +2 -0
  138. package/dist/roles/operations.d.ts +8 -0
  139. package/dist/roles/postgresRoleStore.d.ts +86 -0
  140. package/dist/roles/resolver.d.ts +17 -0
  141. package/dist/roles/routes.d.ts +106 -0
  142. package/dist/roles/types.d.ts +14 -0
  143. package/dist/routes/authorize.d.ts +102 -0
  144. package/dist/routes/callback.d.ts +64 -0
  145. package/dist/routes/profile.d.ts +70 -0
  146. package/dist/routes/protectRoute.d.ts +51 -0
  147. package/dist/routes/refresh.d.ts +74 -0
  148. package/dist/routes/revoke.d.ts +73 -0
  149. package/dist/routes/sessions.d.ts +103 -0
  150. package/dist/routes/signout.d.ts +70 -0
  151. package/dist/routes/stepUp.d.ts +48 -0
  152. package/dist/routes/userStatus.d.ts +72 -0
  153. package/dist/scim/config.d.ts +57 -0
  154. package/dist/scim/extensions.d.ts +30 -0
  155. package/dist/scim/inMemoryScimTokenStore.d.ts +2 -0
  156. package/dist/scim/postgresScimTokenStore.d.ts +86 -0
  157. package/dist/scim/routes.d.ts +366 -0
  158. package/dist/scim/serialize.d.ts +83 -0
  159. package/dist/scim/types.d.ts +54 -0
  160. package/dist/session/access.d.ts +33 -0
  161. package/dist/session/anonymous.d.ts +12 -0
  162. package/dist/session/cleanup.d.ts +45 -0
  163. package/dist/session/impersonation.d.ts +34 -0
  164. package/dist/session/inMemoryStore.d.ts +7 -0
  165. package/dist/session/multiSession.d.ts +27 -0
  166. package/dist/session/neonStore.d.ts +513 -0
  167. package/dist/session/promote.d.ts +23 -0
  168. package/dist/session/redisStore.d.ts +6 -0
  169. package/dist/session/sessionsConfig.d.ts +9 -0
  170. package/dist/session/state.d.ts +33 -0
  171. package/dist/session/types.d.ts +21 -0
  172. package/dist/session/userSessions.d.ts +19 -0
  173. package/dist/sso/config.d.ts +149 -0
  174. package/dist/sso/discoveryRoute.d.ts +63 -0
  175. package/dist/sso/inMemorySamlServiceProviderStore.d.ts +2 -0
  176. package/dist/sso/inMemorySsoConnectionStore.d.ts +2 -0
  177. package/dist/sso/oidcRoutes.d.ts +98 -0
  178. package/dist/sso/postgresSamlServiceProviderStore.d.ts +101 -0
  179. package/dist/sso/postgresSsoConnectionStore.d.ts +116 -0
  180. package/dist/sso/samlIdpRoutes.d.ts +139 -0
  181. package/dist/sso/samlRoutes.d.ts +179 -0
  182. package/dist/sso/types.d.ts +53 -0
  183. package/dist/stores/postgres.d.ts +5 -0
  184. package/dist/stores/redis.d.ts +5 -0
  185. package/dist/telemetry/tracing.d.ts +15 -0
  186. package/dist/tenancy.d.ts +9 -0
  187. package/dist/typeGuards.d.ts +6 -0
  188. package/dist/typebox.d.ts +4 -0
  189. package/dist/types.d.ts +421 -0
  190. package/dist/utils.d.ts +45 -0
  191. package/dist/vault/config.d.ts +20 -0
  192. package/dist/vault/inMemoryVaultStore.d.ts +2 -0
  193. package/dist/vault/postgresVaultStore.d.ts +86 -0
  194. package/dist/vault/types.d.ts +14 -0
  195. package/dist/vc/inMemoryVpStores.d.ts +2 -0
  196. package/dist/vc/openid4vp.d.ts +82 -0
  197. package/dist/vc/postgresVcStores.d.ts +300 -0
  198. package/dist/vc/sdJwt.d.ts +37 -0
  199. package/dist/vc/statusList.d.ts +29 -0
  200. package/dist/vc/statusListRoutes.d.ts +63 -0
  201. package/dist/vc/vpRoutes.d.ts +120 -0
  202. package/dist/webauthn/adapter.d.ts +59 -0
  203. package/dist/webauthn/config.d.ts +36 -0
  204. package/dist/webauthn/inMemoryWebAuthnCredentialStore.d.ts +2 -0
  205. package/dist/webauthn/postgresWebAuthnCredentialStore.d.ts +146 -0
  206. package/dist/webauthn/routes.d.ts +155 -0
  207. package/dist/webauthn/types.d.ts +17 -0
  208. package/dist/webhooks/config.d.ts +34 -0
  209. package/dist/webhooks/dispatcher.d.ts +3 -0
  210. package/dist/webhooks/inMemoryStore.d.ts +2 -0
  211. package/dist/webhooks/postgresStore.d.ts +116 -0
  212. package/dist/webhooks/sign.d.ts +11 -0
  213. package/dist/webhooks/types.d.ts +25 -0
  214. package/package.json +7 -2
@@ -0,0 +1,3233 @@
1
+ // @bun
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
12
+ var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
20
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
21
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ for (let key of __getOwnPropNames(mod))
23
+ if (!__hasOwnProp.call(to, key))
24
+ __defProp(to, key, {
25
+ get: __accessProp.bind(mod, key),
26
+ enumerable: true
27
+ });
28
+ if (canCache)
29
+ cache.set(mod, to);
30
+ return to;
31
+ };
32
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, {
40
+ get: all[name],
41
+ enumerable: true,
42
+ configurable: true,
43
+ set: __exportSetter.bind(all, name)
44
+ });
45
+ };
46
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
+ var __require = import.meta.require;
48
+
49
+ // node_modules/citra/dist/index.js
50
+ var BASE64_BLOCK_SIZE = 4;
51
+ var NUM_GENERATOR_BYTES = 32;
52
+ var anilistProfileQuery = `query {
53
+ Viewer {
54
+ id
55
+ name
56
+ about
57
+ avatar {
58
+ large
59
+ medium
60
+ }
61
+ bannerImage
62
+ siteUrl
63
+ createdAt
64
+ updatedAt
65
+ donatorTier
66
+ donatorBadge
67
+ unreadNotificationCount
68
+ options {
69
+ titleLanguage
70
+ displayAdultContent
71
+ airingNotifications
72
+ profileColor
73
+ activityMergeTime
74
+ staffNameLanguage
75
+ }
76
+ mediaListOptions {
77
+ scoreFormat
78
+ rowOrder
79
+ animeList {
80
+ sectionOrder
81
+ customLists
82
+ advancedScoringEnabled
83
+ }
84
+ mangaList {
85
+ sectionOrder
86
+ customLists
87
+ advancedScoringEnabled
88
+ }
89
+ }
90
+ statistics {
91
+ anime {
92
+ count
93
+ meanScore
94
+ minutesWatched
95
+ episodesWatched
96
+ }
97
+ manga {
98
+ count
99
+ meanScore
100
+ chaptersRead
101
+ volumesRead
102
+ }
103
+ }
104
+ favourites {
105
+ anime {
106
+ nodes {
107
+ id
108
+ title {
109
+ romaji
110
+ english
111
+ }
112
+ siteUrl
113
+ }
114
+ }
115
+ manga {
116
+ nodes {
117
+ id
118
+ title {
119
+ romaji
120
+ english
121
+ }
122
+ siteUrl
123
+ }
124
+ }
125
+ characters {
126
+ nodes {
127
+ id
128
+ name {
129
+ full
130
+ }
131
+ image {
132
+ large
133
+ }
134
+ }
135
+ }
136
+ staff {
137
+ nodes {
138
+ id
139
+ name {
140
+ full
141
+ }
142
+ image {
143
+ large
144
+ }
145
+ }
146
+ }
147
+ studios {
148
+ nodes {
149
+ id
150
+ name
151
+ siteUrl
152
+ }
153
+ }
154
+ }
155
+ isFollower
156
+ isFollowing
157
+ }
158
+ }`;
159
+ var defineProviders = (providers) => providers;
160
+ var defineProvider = (config) => config;
161
+ var providers = defineProviders({
162
+ "42": {
163
+ authorizationUrl: "https://api.intra.42.fr/oauth/authorize",
164
+ isOIDC: false,
165
+ isRefreshable: true,
166
+ profileRequest: {
167
+ authIn: "header",
168
+ encoding: "application/json",
169
+ method: "GET",
170
+ url: "https://api.intra.42.fr/v2/me"
171
+ },
172
+ scopeRequired: false,
173
+ subject: ["id"],
174
+ subjectType: "string",
175
+ tokenRequest: {
176
+ authIn: "body",
177
+ encoding: "application/x-www-form-urlencoded",
178
+ url: "https://api.intra.42.fr/oauth/token"
179
+ }
180
+ },
181
+ amazoncognito: {
182
+ authorizationUrl: "https://${domain}/oauth2/authorize",
183
+ isOIDC: true,
184
+ isRefreshable: true,
185
+ PKCEMethod: "S256",
186
+ profileRequest: {
187
+ authIn: "header",
188
+ encoding: "application/json",
189
+ method: "GET",
190
+ url: (config) => `https://${config.domain}/oauth2/userInfo`
191
+ },
192
+ revocationRequest: {
193
+ authIn: "body",
194
+ encoding: "application/json",
195
+ tokenParamName: "token",
196
+ url: (config) => `https://${config.domain}/oauth2/revoke`
197
+ },
198
+ scopeRequired: false,
199
+ subject: ["id"],
200
+ subjectType: "string",
201
+ tokenRequest: {
202
+ authIn: "body",
203
+ encoding: "application/x-www-form-urlencoded",
204
+ url: (config) => `https://${config.domain}/oauth2/token`
205
+ }
206
+ },
207
+ anilist: {
208
+ authorizationUrl: "https://anilist.co/api/v2/oauth/authorize",
209
+ isOIDC: false,
210
+ isRefreshable: true,
211
+ profileRequest: {
212
+ authIn: "header",
213
+ body: {
214
+ query: anilistProfileQuery
215
+ },
216
+ encoding: "application/json",
217
+ headers: {
218
+ Accept: "application/json",
219
+ "Content-Type": "application/json"
220
+ },
221
+ method: "POST",
222
+ url: "https://graphql.anilist.co"
223
+ },
224
+ scopeRequired: false,
225
+ subject: ["data", "Viewer", "id"],
226
+ subjectType: "number",
227
+ tokenRequest: {
228
+ authIn: "body",
229
+ encoding: "application/x-www-form-urlencoded",
230
+ url: "https://anilist.co/api/v2/oauth/token"
231
+ }
232
+ },
233
+ apple: {
234
+ authorizationUrl: "https://appleid.apple.com/auth/authorize",
235
+ isOIDC: true,
236
+ isRefreshable: true,
237
+ PKCEMethod: "S256",
238
+ profileRequest: {
239
+ authIn: "header",
240
+ encoding: "application/json",
241
+ method: "GET",
242
+ url: "https://appleid.apple.com/auth/userinfo"
243
+ },
244
+ scopeRequired: false,
245
+ subject: ["id"],
246
+ subjectType: "string",
247
+ tokenRequest: {
248
+ authIn: "body",
249
+ encoding: "application/x-www-form-urlencoded",
250
+ url: "https://appleid.apple.com/auth/token"
251
+ }
252
+ },
253
+ atlassian: {
254
+ authorizationUrl: "https://auth.atlassian.com/authorize",
255
+ createAuthorizationURLSearchParams: {
256
+ audience: "api.atlassian.com"
257
+ },
258
+ email: ["email"],
259
+ fullName: ["name"],
260
+ isOIDC: false,
261
+ isRefreshable: true,
262
+ picture: ["picture"],
263
+ profileRequest: {
264
+ authIn: "header",
265
+ encoding: "application/json",
266
+ method: "GET",
267
+ url: "https://api.atlassian.com/me"
268
+ },
269
+ scopeRequired: true,
270
+ subject: ["account_id"],
271
+ subjectType: "string",
272
+ tokenRequest: {
273
+ authIn: "body",
274
+ encoding: "application/x-www-form-urlencoded",
275
+ url: "https://auth.atlassian.com/oauth/token"
276
+ }
277
+ },
278
+ attio: {
279
+ authorizationUrl: "https://app.attio.com/authorize",
280
+ isOIDC: false,
281
+ isRefreshable: true,
282
+ profileRequest: {
283
+ authIn: "header",
284
+ encoding: "application/json",
285
+ method: "GET",
286
+ url: "https://api.attio.com/v2/self"
287
+ },
288
+ scopeRequired: true,
289
+ subject: ["workspace_id"],
290
+ subjectType: "string",
291
+ tokenRequest: {
292
+ authIn: "body",
293
+ encoding: "application/x-www-form-urlencoded",
294
+ url: "https://app.attio.com/oauth/token"
295
+ }
296
+ },
297
+ auth0: {
298
+ authorizationUrl: (config) => `https://${config.domain}/authorize`,
299
+ isOIDC: true,
300
+ isRefreshable: true,
301
+ PKCEMethod: "S256",
302
+ profileRequest: {
303
+ authIn: "header",
304
+ encoding: "application/json",
305
+ method: "GET",
306
+ url: (config) => `https://${config.domain}/userinfo`
307
+ },
308
+ revocationRequest: {
309
+ authIn: "body",
310
+ body: new URLSearchParams({
311
+ token_type_hint: "refresh_token"
312
+ }),
313
+ encoding: "application/json",
314
+ tokenParamName: "token",
315
+ url: (config) => `https://${config.domain}/oauth/revoke`
316
+ },
317
+ scopeRequired: false,
318
+ subject: ["id"],
319
+ subjectType: "string",
320
+ tokenRequest: {
321
+ authIn: "body",
322
+ encoding: "application/x-www-form-urlencoded",
323
+ url: (config) => `https://${config.domain}/oauth/token`
324
+ }
325
+ },
326
+ authentik: {
327
+ authorizationUrl: (config) => `https://${config.baseURL}/oauth/authorize`,
328
+ isOIDC: true,
329
+ isRefreshable: true,
330
+ PKCEMethod: "S256",
331
+ profileRequest: {
332
+ authIn: "header",
333
+ encoding: "application/json",
334
+ method: "GET",
335
+ url: (config) => `https://${config.baseURL}/api/v3/user/`
336
+ },
337
+ scopeRequired: false,
338
+ subject: ["id"],
339
+ subjectType: "string",
340
+ tokenRequest: {
341
+ authIn: "body",
342
+ encoding: "application/x-www-form-urlencoded",
343
+ url: (config) => `https://${config.baseURL}/oauth/token`
344
+ }
345
+ },
346
+ autodesk: {
347
+ authorizationUrl: "https://developer.api.autodesk.com/authentication/v2/authorize",
348
+ email: ["email"],
349
+ familyName: ["family_name"],
350
+ fullName: ["name"],
351
+ givenName: ["given_name"],
352
+ isOIDC: true,
353
+ isRefreshable: true,
354
+ picture: ["picture"],
355
+ PKCEMethod: "S256",
356
+ profileRequest: {
357
+ authIn: "header",
358
+ encoding: "application/json",
359
+ method: "GET",
360
+ url: "https://api.userprofile.autodesk.com/userinfo"
361
+ },
362
+ scopeRequired: false,
363
+ subject: ["id"],
364
+ subjectType: "string",
365
+ tokenRequest: {
366
+ authIn: "body",
367
+ encoding: "application/x-www-form-urlencoded",
368
+ url: "https://developer.api.autodesk.com/authentication/v2/token"
369
+ }
370
+ },
371
+ azureadb2c: {
372
+ authorizationUrl: (config) => `https://${config.tenantSubdomain}.b2clogin.com/${config.tenantSubdomain}.onmicrosoft.com/${config.policy}/oauth2/v2.0/authorize`,
373
+ isOIDC: true,
374
+ isRefreshable: true,
375
+ PKCEMethod: "S256",
376
+ scopeRequired: false,
377
+ subject: ["sub"],
378
+ subjectType: "string",
379
+ tokenRequest: {
380
+ authIn: "body",
381
+ encoding: "application/x-www-form-urlencoded",
382
+ url: (config) => `https://${config.tenantSubdomain}.b2clogin.com/${config.tenantSubdomain}.onmicrosoft.com/${config.policy}/oauth2/v2.0/token`
383
+ }
384
+ },
385
+ battlenet: {
386
+ authorizationUrl: "https://oauth.battle.net/authorize",
387
+ isOIDC: true,
388
+ isRefreshable: false,
389
+ profileRequest: {
390
+ authIn: "header",
391
+ encoding: "application/json",
392
+ method: "GET",
393
+ url: "https://oauth.battle.net/userinfo"
394
+ },
395
+ scopeRequired: false,
396
+ subject: ["id"],
397
+ subjectType: "string",
398
+ tokenRequest: {
399
+ authIn: "body",
400
+ encoding: "application/x-www-form-urlencoded",
401
+ url: "https://oauth.battle.net/token"
402
+ }
403
+ },
404
+ bitbucket: {
405
+ authorizationUrl: "https://bitbucket.org/site/oauth2/authorize",
406
+ fullName: ["display_name"],
407
+ isOIDC: false,
408
+ isRefreshable: true,
409
+ picture: ["links", "avatar", "href"],
410
+ profileRequest: {
411
+ authIn: "header",
412
+ encoding: "application/json",
413
+ method: "GET",
414
+ url: "https://api.bitbucket.org/2.0/user"
415
+ },
416
+ scopeRequired: false,
417
+ subject: ["uuid"],
418
+ subjectType: "string",
419
+ tokenRequest: {
420
+ authIn: "body",
421
+ encoding: "application/x-www-form-urlencoded",
422
+ url: "https://bitbucket.org/site/oauth2/access_token"
423
+ }
424
+ },
425
+ box: {
426
+ authorizationUrl: "https://account.box.com/api/oauth2/authorize",
427
+ email: ["login"],
428
+ fullName: ["name"],
429
+ isOIDC: false,
430
+ isRefreshable: true,
431
+ picture: ["avatar_url"],
432
+ profileRequest: {
433
+ authIn: "header",
434
+ encoding: "application/json",
435
+ method: "GET",
436
+ url: "https://api.box.com/2.0/users/me"
437
+ },
438
+ revocationRequest: {
439
+ authIn: "body",
440
+ encoding: "application/json",
441
+ tokenParamName: "token",
442
+ url: "https://api.box.com/oauth2/revoke"
443
+ },
444
+ scopeRequired: false,
445
+ subject: ["id"],
446
+ subjectType: "string",
447
+ tokenRequest: {
448
+ authIn: "body",
449
+ encoding: "application/x-www-form-urlencoded",
450
+ url: "https://api.box.com/oauth2/token"
451
+ }
452
+ },
453
+ bungie: {
454
+ authorizationUrl: "https://www.bungie.net/en/OAuth/Authorize",
455
+ isOIDC: false,
456
+ isRefreshable: true,
457
+ profileRequest: {
458
+ authIn: "header",
459
+ encoding: "application/json",
460
+ headers: {
461
+ "X-API-Key": "<YOUR_API_KEY>"
462
+ },
463
+ method: "GET",
464
+ url: "https://www.bungie.net/Platform/User/GetCurrentBungieNetUser"
465
+ },
466
+ scopeRequired: false,
467
+ subject: ["Response", "membershipId"],
468
+ subjectType: "number",
469
+ tokenRequest: {
470
+ authIn: "body",
471
+ encoding: "application/x-www-form-urlencoded",
472
+ url: "https://www.bungie.net/Platform/App/OAuth/token"
473
+ }
474
+ },
475
+ calendly: {
476
+ authorizationUrl: "https://auth.calendly.com/oauth/authorize",
477
+ email: ["resource", "email"],
478
+ fullName: ["resource", "name"],
479
+ isOIDC: false,
480
+ isRefreshable: true,
481
+ profileRequest: {
482
+ authIn: "header",
483
+ encoding: "application/json",
484
+ method: "GET",
485
+ url: "https://api.calendly.com/users/me"
486
+ },
487
+ scopeRequired: false,
488
+ subject: ["resource", "uri"],
489
+ subjectType: "string",
490
+ tokenRequest: {
491
+ authIn: "body",
492
+ encoding: "application/x-www-form-urlencoded",
493
+ url: "https://auth.calendly.com/oauth/token"
494
+ }
495
+ },
496
+ close: {
497
+ authorizationUrl: "https://app.close.com/oauth2/authorize/",
498
+ isOIDC: false,
499
+ isRefreshable: true,
500
+ profileRequest: {
501
+ authIn: "header",
502
+ encoding: "application/json",
503
+ method: "GET",
504
+ url: "https://api.close.com/api/v1/me/"
505
+ },
506
+ scopeRequired: true,
507
+ subject: ["id"],
508
+ subjectType: "string",
509
+ tokenRequest: {
510
+ authIn: "body",
511
+ encoding: "application/x-www-form-urlencoded",
512
+ url: "https://api.close.com/oauth2/token/"
513
+ }
514
+ },
515
+ coinbase: {
516
+ authorizationUrl: "https://www.coinbase.com/oauth/authorize",
517
+ isOIDC: false,
518
+ isRefreshable: true,
519
+ profileRequest: {
520
+ authIn: "header",
521
+ encoding: "application/json",
522
+ method: "GET",
523
+ url: "https://api.coinbase.com/v2/user"
524
+ },
525
+ scopeRequired: false,
526
+ subject: ["data", "id"],
527
+ subjectType: "number",
528
+ tokenRequest: {
529
+ authIn: "body",
530
+ encoding: "application/x-www-form-urlencoded",
531
+ url: "https://api.coinbase.com/oauth/token"
532
+ }
533
+ },
534
+ discord: {
535
+ authorizationUrl: "https://discord.com/api/oauth2/authorize",
536
+ email: ["email"],
537
+ isOIDC: true,
538
+ isRefreshable: true,
539
+ picture: ["avatar"],
540
+ PKCEMethod: "S256",
541
+ profileRequest: {
542
+ authIn: "header",
543
+ encoding: "application/json",
544
+ method: "GET",
545
+ url: "https://discord.com/api/users/@me"
546
+ },
547
+ scopeRequired: true,
548
+ subject: ["id"],
549
+ subjectType: "string",
550
+ tokenRequest: {
551
+ authIn: "body",
552
+ encoding: "application/x-www-form-urlencoded",
553
+ url: "https://discord.com/api/oauth2/token"
554
+ }
555
+ },
556
+ donationalerts: {
557
+ authorizationUrl: "https://www.donationalerts.com/oauth/authorize",
558
+ email: ["data", "email"],
559
+ isOIDC: false,
560
+ isRefreshable: true,
561
+ picture: ["data", "avatar"],
562
+ profileRequest: {
563
+ authIn: "header",
564
+ encoding: "application/json",
565
+ method: "GET",
566
+ url: "https://www.donationalerts.com/api/v1/user/oauth"
567
+ },
568
+ scopeRequired: false,
569
+ subject: ["data", "id"],
570
+ subjectType: "number",
571
+ tokenRequest: {
572
+ authIn: "body",
573
+ encoding: "application/x-www-form-urlencoded",
574
+ url: "https://www.donationalerts.com/oauth/token"
575
+ }
576
+ },
577
+ dribbble: {
578
+ authorizationUrl: "https://dribbble.com/oauth/authorize",
579
+ isOIDC: false,
580
+ isRefreshable: false,
581
+ profileRequest: {
582
+ authIn: "header",
583
+ encoding: "application/json",
584
+ method: "GET",
585
+ url: "https://api.dribbble.com/v2/user"
586
+ },
587
+ scopeRequired: false,
588
+ subject: ["id"],
589
+ subjectType: "number",
590
+ tokenRequest: {
591
+ authIn: "body",
592
+ encoding: "application/x-www-form-urlencoded",
593
+ url: "https://dribbble.com/oauth/token"
594
+ }
595
+ },
596
+ dropbox: {
597
+ authorizationUrl: "https://www.dropbox.com/oauth2/authorize",
598
+ email: ["email"],
599
+ familyName: ["name", "surname"],
600
+ fullName: ["name", "display_name"],
601
+ givenName: ["name", "given_name"],
602
+ isOIDC: false,
603
+ isRefreshable: true,
604
+ profileRequest: {
605
+ authIn: "header",
606
+ encoding: "application/json",
607
+ method: "POST",
608
+ url: "https://api.dropboxapi.com/2/users/get_current_account"
609
+ },
610
+ revocationRequest: {
611
+ authIn: "header",
612
+ encoding: "application/json",
613
+ url: "https://api.dropboxapi.com/2/auth/token/revoke"
614
+ },
615
+ scopeRequired: false,
616
+ subject: ["account_id"],
617
+ subjectType: "string",
618
+ tokenRequest: {
619
+ authIn: "body",
620
+ encoding: "application/x-www-form-urlencoded",
621
+ url: "https://api.dropboxapi.com/oauth2/token"
622
+ }
623
+ },
624
+ epicgames: {
625
+ authorizationUrl: "https://www.epicgames.com/id/authorize",
626
+ isOIDC: false,
627
+ isRefreshable: true,
628
+ profileRequest: {
629
+ authIn: "header",
630
+ encoding: "application/json",
631
+ method: "GET",
632
+ url: "https://api.epicgames.dev/epic/oauth/v2/userInfo"
633
+ },
634
+ scopeRequired: false,
635
+ subject: ["account_id"],
636
+ subjectType: "number",
637
+ tokenRequest: {
638
+ authIn: "body",
639
+ encoding: "application/x-www-form-urlencoded",
640
+ url: "https://api.epicgames.dev/epic/oauth/v1/token"
641
+ }
642
+ },
643
+ etsy: {
644
+ authorizationUrl: "https://www.etsy.com/oauth/connect",
645
+ isOIDC: false,
646
+ isRefreshable: true,
647
+ profileRequest: {
648
+ authIn: "header",
649
+ encoding: "application/json",
650
+ method: "GET",
651
+ url: "https://openapi.etsy.com/v3/application/users/me"
652
+ },
653
+ scopeRequired: false,
654
+ subject: ["results", "0", "user_id"],
655
+ subjectType: "number",
656
+ tokenRequest: {
657
+ authIn: "body",
658
+ encoding: "application/x-www-form-urlencoded",
659
+ url: "https://api.etsy.com/v3/public/oauth/token"
660
+ }
661
+ },
662
+ facebook: {
663
+ authorizationUrl: "https://www.facebook.com/v16.0/dialog/oauth",
664
+ email: ["email"],
665
+ familyName: ["family_name"],
666
+ fullName: ["name"],
667
+ givenName: ["given_name"],
668
+ isOIDC: true,
669
+ isRefreshable: false,
670
+ picture: ["picture"],
671
+ PKCEMethod: "S256",
672
+ profileRequest: {
673
+ authIn: "query",
674
+ encoding: "application/json",
675
+ method: "GET",
676
+ searchParams: [["fields", "id,name,email,picture"]],
677
+ url: "https://graph.facebook.com/me"
678
+ },
679
+ scopeRequired: false,
680
+ subject: ["sub"],
681
+ subjectBySource: {
682
+ idToken: ["sub"],
683
+ profile: ["id"]
684
+ },
685
+ subjectType: "string",
686
+ tokenRequest: {
687
+ authIn: "body",
688
+ encoding: "application/x-www-form-urlencoded",
689
+ url: "https://graph.facebook.com/v16.0/oauth/access_token"
690
+ }
691
+ },
692
+ figma: {
693
+ authorizationUrl: "https://www.figma.com/oauth",
694
+ email: ["email"],
695
+ isOIDC: false,
696
+ isRefreshable: true,
697
+ picture: ["img_url"],
698
+ PKCEMethod: "S256",
699
+ profileRequest: {
700
+ authIn: "header",
701
+ encoding: "application/json",
702
+ method: "GET",
703
+ url: "https://api.figma.com/v1/me"
704
+ },
705
+ scopeRequired: true,
706
+ subject: ["id"],
707
+ subjectType: "string",
708
+ tokenRequest: {
709
+ authIn: "body",
710
+ encoding: "application/x-www-form-urlencoded",
711
+ url: "https://api.figma.com/v1/oauth/token"
712
+ }
713
+ },
714
+ gitea: {
715
+ authorizationUrl: (config) => `${config.baseURL}/login/oauth/authorize`,
716
+ isOIDC: true,
717
+ isRefreshable: true,
718
+ PKCEMethod: "S256",
719
+ profileRequest: {
720
+ authIn: "header",
721
+ encoding: "application/json",
722
+ method: "GET",
723
+ url: (config) => `${config.baseURL}/api/v1/user`
724
+ },
725
+ scopeRequired: false,
726
+ subject: ["id"],
727
+ subjectType: "string",
728
+ tokenRequest: {
729
+ authIn: "body",
730
+ encoding: "application/x-www-form-urlencoded",
731
+ url: (config) => `${config.baseURL}/login/oauth/access_token`
732
+ }
733
+ },
734
+ github: {
735
+ authorizationUrl: "https://github.com/login/oauth/authorize",
736
+ email: ["email"],
737
+ isOIDC: false,
738
+ isRefreshable: false,
739
+ picture: ["avatar_url"],
740
+ profileRequest: {
741
+ authIn: "header",
742
+ encoding: "application/json",
743
+ method: "GET",
744
+ url: "https://api.github.com/user"
745
+ },
746
+ scopeRequired: false,
747
+ subject: ["id"],
748
+ subjectType: "number",
749
+ tokenRequest: {
750
+ authIn: "body",
751
+ encoding: "application/x-www-form-urlencoded",
752
+ url: "https://github.com/login/oauth/access_token"
753
+ }
754
+ },
755
+ gitlab: {
756
+ authorizationUrl: (config) => `${config.baseURL}/oauth/authorize`,
757
+ email: ["email"],
758
+ fullName: ["name"],
759
+ isOIDC: true,
760
+ isRefreshable: true,
761
+ picture: ["picture"],
762
+ PKCEMethod: "S256",
763
+ profileRequest: {
764
+ authIn: "header",
765
+ encoding: "application/json",
766
+ method: "GET",
767
+ url: "https://gitlab.com/api/v4/user"
768
+ },
769
+ revocationRequest: {
770
+ authIn: "body",
771
+ encoding: "application/json",
772
+ tokenParamName: "token",
773
+ url: (config) => `${config.baseURL}/oauth/revoke`
774
+ },
775
+ scopeRequired: false,
776
+ subject: ["id"],
777
+ subjectType: "string",
778
+ tokenRequest: {
779
+ authIn: "body",
780
+ encoding: "application/x-www-form-urlencoded",
781
+ url: (config) => `${config.baseURL}/oauth/token`
782
+ }
783
+ },
784
+ gohighlevel: {
785
+ authorizationUrl: "https://marketplace.gohighlevel.com/v2/oauth/chooselocation",
786
+ isOIDC: false,
787
+ isRefreshable: true,
788
+ profileRequest: {
789
+ authIn: "header",
790
+ encoding: "application/json",
791
+ headers: {
792
+ Version: "2021-07-28"
793
+ },
794
+ method: "GET",
795
+ url: "https://services.leadconnectorhq.com/users/me"
796
+ },
797
+ scopeRequired: true,
798
+ subject: ["locationId"],
799
+ subjectBySource: {
800
+ tokenResponse: ["locationId"]
801
+ },
802
+ subjectType: "string",
803
+ tokenRequest: {
804
+ authIn: "body",
805
+ encoding: "application/x-www-form-urlencoded",
806
+ url: "https://services.leadconnectorhq.com/oauth/token"
807
+ }
808
+ },
809
+ google: {
810
+ authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
811
+ email: ["email"],
812
+ familyName: ["family_name"],
813
+ fullName: ["name"],
814
+ givenName: ["given_name"],
815
+ isOIDC: true,
816
+ isRefreshable: true,
817
+ picture: ["picture"],
818
+ PKCEMethod: "S256",
819
+ profileRequest: {
820
+ authIn: "header",
821
+ encoding: "application/json",
822
+ method: "GET",
823
+ url: "https://openidconnect.googleapis.com/v1/userinfo"
824
+ },
825
+ revocationRequest: {
826
+ authIn: "body",
827
+ encoding: "application/json",
828
+ tokenParamName: "token",
829
+ url: "https://oauth2.googleapis.com/revoke"
830
+ },
831
+ scopeRequired: true,
832
+ subject: ["sub"],
833
+ subjectBySource: {
834
+ idToken: ["sub"],
835
+ profile: ["sub"]
836
+ },
837
+ subjectType: "string",
838
+ tokenRequest: {
839
+ authIn: "body",
840
+ encoding: "application/x-www-form-urlencoded",
841
+ url: "https://oauth2.googleapis.com/token"
842
+ }
843
+ },
844
+ hubspot: {
845
+ authorizationUrl: "https://app.hubspot.com/oauth/authorize",
846
+ isOIDC: false,
847
+ isRefreshable: true,
848
+ profileRequest: {
849
+ authIn: "path",
850
+ encoding: "application/json",
851
+ method: "GET",
852
+ url: "https://api.hubapi.com/oauth/v1/access-tokens"
853
+ },
854
+ scopeRequired: true,
855
+ subject: ["hub_id"],
856
+ subjectType: "number",
857
+ tokenRequest: {
858
+ authIn: "body",
859
+ encoding: "application/x-www-form-urlencoded",
860
+ url: "https://api.hubapi.com/oauth/v1/token"
861
+ }
862
+ },
863
+ intuit: {
864
+ authorizationUrl: "https://appcenter.intuit.com/connect/oauth2",
865
+ isOIDC: true,
866
+ isRefreshable: true,
867
+ profileRequest: {
868
+ authIn: "header",
869
+ encoding: "application/json",
870
+ method: "GET",
871
+ url: (config) => config.environment === "production" ? "https://accounts.platform.intuit.com/v1/openid_connect/userinfo" : "https://sandbox-accounts.platform.intuit.com/v1/openid_connect/userinfo"
872
+ },
873
+ revocationRequest: {
874
+ authIn: "body",
875
+ encoding: "application/json",
876
+ headers: (config) => ({
877
+ Authorization: `Basic ${encodeBase64(`${config.clientId}:${config.clientSecret}`)}`
878
+ }),
879
+ tokenParamName: "token",
880
+ url: "https://developer.api.intuit.com/v2/oauth2/tokens/revoke"
881
+ },
882
+ scopeRequired: true,
883
+ subject: ["id"],
884
+ subjectType: "string",
885
+ tokenRequest: {
886
+ authIn: "body",
887
+ encoding: "application/x-www-form-urlencoded",
888
+ url: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
889
+ }
890
+ },
891
+ kakao: {
892
+ authorizationUrl: "https://kauth.kakao.com/oauth/authorize",
893
+ isOIDC: true,
894
+ isRefreshable: true,
895
+ picture: ["picture"],
896
+ PKCEMethod: "S256",
897
+ profileRequest: {
898
+ authIn: "header",
899
+ encoding: "application/json",
900
+ method: "GET",
901
+ url: "https://kapi.kakao.com/v2/user/me"
902
+ },
903
+ scopeRequired: false,
904
+ subject: ["id"],
905
+ subjectType: "string",
906
+ tokenRequest: {
907
+ authIn: "body",
908
+ encoding: "application/x-www-form-urlencoded",
909
+ url: "https://kauth.kakao.com/oauth/token"
910
+ }
911
+ },
912
+ keycloak: {
913
+ authorizationUrl: (config) => `${config.realmURL}/protocol/openid-connect/auth`,
914
+ isOIDC: true,
915
+ isRefreshable: true,
916
+ PKCEMethod: "S256",
917
+ profileRequest: {
918
+ authIn: "header",
919
+ encoding: "application/json",
920
+ method: "GET",
921
+ url: "https://api.kick.com/v1/user"
922
+ },
923
+ revocationRequest: {
924
+ authIn: "body",
925
+ encoding: "application/json",
926
+ tokenParamName: "token",
927
+ url: (config) => `${config.realmURL}/protocol/openid-connect/revoke`
928
+ },
929
+ scopeRequired: false,
930
+ subject: ["id"],
931
+ subjectType: "string",
932
+ tokenRequest: {
933
+ authIn: "body",
934
+ encoding: "application/x-www-form-urlencoded",
935
+ url: (config) => `${config.realmURL}/protocol/openid-connect/token`
936
+ }
937
+ },
938
+ kick: {
939
+ authorizationUrl: "https://id.kick.com/oauth/authorize",
940
+ email: ["data", "email"],
941
+ isOIDC: false,
942
+ isRefreshable: true,
943
+ picture: ["data", "profile_picture"],
944
+ PKCEMethod: "S256",
945
+ profileRequest: {
946
+ authIn: "header",
947
+ encoding: "application/json",
948
+ method: "GET",
949
+ url: "https://api.kick.com/public/v1/users"
950
+ },
951
+ revocationRequest: {
952
+ authIn: "body",
953
+ encoding: "application/json",
954
+ tokenParamName: "token",
955
+ url: "https://id.kick.com/oauth/revoke"
956
+ },
957
+ scopeRequired: true,
958
+ subject: ["data", "user_id"],
959
+ subjectType: "number",
960
+ tokenRequest: {
961
+ authIn: "body",
962
+ encoding: "application/x-www-form-urlencoded",
963
+ url: "https://id.kick.com/oauth/token"
964
+ }
965
+ },
966
+ lichess: {
967
+ authorizationUrl: "https://lichess.org/oauth/authorize",
968
+ isOIDC: false,
969
+ isRefreshable: false,
970
+ PKCEMethod: "S256",
971
+ profileRequest: {
972
+ authIn: "header",
973
+ encoding: "application/json",
974
+ method: "GET",
975
+ url: "https://lichess.org/api/account"
976
+ },
977
+ scopeRequired: false,
978
+ subject: ["id"],
979
+ subjectType: "string",
980
+ tokenRequest: {
981
+ authIn: "body",
982
+ encoding: "application/x-www-form-urlencoded",
983
+ url: "https://lichess.org/api/token"
984
+ }
985
+ },
986
+ line: {
987
+ authorizationUrl: "https://access.line.me/oauth2/v2.1/authorize",
988
+ isOIDC: true,
989
+ isRefreshable: true,
990
+ PKCEMethod: "S256",
991
+ profileRequest: {
992
+ authIn: "header",
993
+ encoding: "application/json",
994
+ method: "GET",
995
+ url: "https://api.line.me/v2/profile"
996
+ },
997
+ scopeRequired: true,
998
+ subject: ["id"],
999
+ subjectType: "string",
1000
+ tokenRequest: {
1001
+ authIn: "body",
1002
+ encoding: "application/x-www-form-urlencoded",
1003
+ url: "https://api.line.me/oauth2/v2.1/token"
1004
+ }
1005
+ },
1006
+ linear: {
1007
+ authorizationUrl: "https://linear.app/oauth/authorize",
1008
+ isOIDC: false,
1009
+ isRefreshable: false,
1010
+ profileRequest: {
1011
+ authIn: "header",
1012
+ body: {
1013
+ query: `query { viewer { id name } }`
1014
+ },
1015
+ encoding: "application/json",
1016
+ headers: {
1017
+ Accept: "application/json",
1018
+ "Content-Type": "application/json"
1019
+ },
1020
+ method: "POST",
1021
+ url: "https://api.linear.app/graphql"
1022
+ },
1023
+ revocationRequest: {
1024
+ authIn: "header",
1025
+ encoding: "application/json",
1026
+ url: "https://api.linear.app/oauth/revoke"
1027
+ },
1028
+ scopeRequired: false,
1029
+ subject: ["data", "viewer", "id"],
1030
+ subjectType: "string",
1031
+ tokenRequest: {
1032
+ authIn: "body",
1033
+ encoding: "application/x-www-form-urlencoded",
1034
+ url: "https://api.linear.app/oauth/token"
1035
+ }
1036
+ },
1037
+ linkedin: {
1038
+ authorizationUrl: "https://www.linkedin.com/oauth/v2/authorization",
1039
+ isOIDC: true,
1040
+ isRefreshable: true,
1041
+ PKCEMethod: "S256",
1042
+ profileRequest: {
1043
+ authIn: "header",
1044
+ encoding: "application/json",
1045
+ method: "GET",
1046
+ url: "https://api.linkedin.com/v2/me"
1047
+ },
1048
+ scopeRequired: true,
1049
+ subject: ["id"],
1050
+ subjectType: "string",
1051
+ tokenRequest: {
1052
+ authIn: "body",
1053
+ encoding: "application/x-www-form-urlencoded",
1054
+ url: "https://www.linkedin.com/oauth/v2/accessToken"
1055
+ }
1056
+ },
1057
+ mastodon: {
1058
+ authorizationUrl: (config) => `${config.baseURL}/oauth/authorize`,
1059
+ isOIDC: false,
1060
+ isRefreshable: false,
1061
+ picture: ["avatar"],
1062
+ PKCEMethod: "S256",
1063
+ profileRequest: {
1064
+ authIn: "header",
1065
+ encoding: "application/json",
1066
+ method: "GET",
1067
+ url: (config) => `${config.baseURL}/api/v1/accounts/verify_credentials`
1068
+ },
1069
+ revocationRequest: {
1070
+ authIn: "body",
1071
+ encoding: "application/json",
1072
+ tokenParamName: "token",
1073
+ url: (config) => `${config.baseURL}/oauth/revoke`
1074
+ },
1075
+ scopeRequired: false,
1076
+ subject: ["id"],
1077
+ subjectType: "string",
1078
+ tokenRequest: {
1079
+ authIn: "body",
1080
+ encoding: "application/x-www-form-urlencoded",
1081
+ url: (config) => `${config.baseURL}/oauth/token`
1082
+ }
1083
+ },
1084
+ mercadolibre: {
1085
+ authorizationUrl: "https://auth.mercadolibre.com/authorization",
1086
+ isOIDC: false,
1087
+ isRefreshable: true,
1088
+ PKCEMethod: "S256",
1089
+ profileRequest: {
1090
+ authIn: "header",
1091
+ encoding: "application/json",
1092
+ method: "GET",
1093
+ url: "https://api.mercadolibre.com/users/me"
1094
+ },
1095
+ scopeRequired: false,
1096
+ subject: ["id"],
1097
+ subjectType: "number",
1098
+ tokenRequest: {
1099
+ authIn: "body",
1100
+ encoding: "application/x-www-form-urlencoded",
1101
+ url: "https://api.mercadolibre.com/oauth/token"
1102
+ }
1103
+ },
1104
+ mercadopago: {
1105
+ authorizationUrl: "https://auth.mercadopago.com/authorization",
1106
+ isOIDC: false,
1107
+ isRefreshable: true,
1108
+ profileRequest: {
1109
+ authIn: "header",
1110
+ encoding: "application/json",
1111
+ method: "GET",
1112
+ url: "https://api.mercadopago.com/v1/users/me"
1113
+ },
1114
+ scopeRequired: false,
1115
+ subject: ["id"],
1116
+ subjectType: "number",
1117
+ tokenRequest: {
1118
+ authIn: "body",
1119
+ encoding: "application/x-www-form-urlencoded",
1120
+ url: "https://api.mercadopago.com/oauth/token"
1121
+ }
1122
+ },
1123
+ microsoftentraexternalid: {
1124
+ authorizationUrl: (config) => `https://${config.tenantSubdomain}.ciamlogin.com/${config.tenantId}/oauth2/v2.0/authorize`,
1125
+ isOIDC: true,
1126
+ isRefreshable: true,
1127
+ PKCEMethod: "S256",
1128
+ scopeRequired: false,
1129
+ subject: ["sub"],
1130
+ subjectType: "string",
1131
+ tokenRequest: {
1132
+ authIn: "body",
1133
+ encoding: "application/x-www-form-urlencoded",
1134
+ url: (config) => `https://${config.tenantSubdomain}.ciamlogin.com/${config.tenantId}/oauth2/v2.0/token`
1135
+ }
1136
+ },
1137
+ microsoftentraid: {
1138
+ authorizationUrl: (config) => `https://login.microsoftonline.com/${config.tenantId}/oauth2/v2.0/authorize`,
1139
+ isOIDC: true,
1140
+ isRefreshable: true,
1141
+ PKCEMethod: "S256",
1142
+ profileRequest: {
1143
+ authIn: "header",
1144
+ encoding: "application/json",
1145
+ method: "GET",
1146
+ url: "https://graph.microsoft.com/oidc/userinfo"
1147
+ },
1148
+ scopeRequired: false,
1149
+ subject: ["sub"],
1150
+ subjectType: "string",
1151
+ tokenRequest: {
1152
+ authIn: "body",
1153
+ encoding: "application/x-www-form-urlencoded",
1154
+ url: (config) => `https://login.microsoftonline.com/${config.tenantId}/oauth2/v2.0/token`
1155
+ }
1156
+ },
1157
+ monday: {
1158
+ authorizationUrl: "https://auth.monday.com/oauth2/authorize",
1159
+ isOIDC: false,
1160
+ isRefreshable: true,
1161
+ profileRequest: {
1162
+ authIn: "header",
1163
+ body: {
1164
+ query: "query { me { id name email } }"
1165
+ },
1166
+ encoding: "application/json",
1167
+ headers: {
1168
+ "Content-Type": "application/json"
1169
+ },
1170
+ method: "POST",
1171
+ url: "https://api.monday.com/v2"
1172
+ },
1173
+ scopeRequired: true,
1174
+ subject: ["data", "me", "id"],
1175
+ subjectType: "number",
1176
+ tokenRequest: {
1177
+ authIn: "body",
1178
+ encoding: "application/x-www-form-urlencoded",
1179
+ url: "https://auth.monday.com/oauth2/token"
1180
+ }
1181
+ },
1182
+ myanimelist: {
1183
+ authorizationUrl: "https://myanimelist.net/v1/oauth2/authorize",
1184
+ isOIDC: false,
1185
+ isRefreshable: true,
1186
+ PKCEMethod: "plain",
1187
+ profileRequest: {
1188
+ authIn: "header",
1189
+ encoding: "application/json",
1190
+ method: "GET",
1191
+ url: "https://api.myanimelist.net/v2/users/@me"
1192
+ },
1193
+ scopeRequired: false,
1194
+ subject: ["id"],
1195
+ subjectType: "number",
1196
+ tokenRequest: {
1197
+ authIn: "body",
1198
+ encoding: "application/x-www-form-urlencoded",
1199
+ url: "https://myanimelist.net/v1/oauth2/token"
1200
+ }
1201
+ },
1202
+ naver: {
1203
+ authorizationUrl: "https://nid.naver.com/oauth2.0/authorize",
1204
+ email: ["response", "email"],
1205
+ fullName: ["response", "name"],
1206
+ isOIDC: false,
1207
+ isRefreshable: true,
1208
+ picture: ["response", "profile_image"],
1209
+ profileRequest: {
1210
+ authIn: "header",
1211
+ encoding: "application/json",
1212
+ method: "GET",
1213
+ url: "https://openapi.naver.com/v1/nid/me"
1214
+ },
1215
+ scopeRequired: false,
1216
+ subject: ["response", "id"],
1217
+ subjectType: "string",
1218
+ tokenRequest: {
1219
+ authIn: "body",
1220
+ encoding: "application/x-www-form-urlencoded",
1221
+ url: "https://nid.naver.com/oauth2.0/token"
1222
+ }
1223
+ },
1224
+ notion: {
1225
+ authorizationUrl: "https://api.notion.com/v1/oauth/authorize",
1226
+ email: ["bot", "owner", "user", "person", "email"],
1227
+ isOIDC: false,
1228
+ isRefreshable: false,
1229
+ picture: ["bot", "owner", "user", "avatar_url"],
1230
+ profileRequest: {
1231
+ authIn: "header",
1232
+ encoding: "application/json",
1233
+ headers: {
1234
+ "Notion-Version": "2022-06-28"
1235
+ },
1236
+ method: "GET",
1237
+ url: "https://api.notion.com/v1/users/me"
1238
+ },
1239
+ scopeRequired: false,
1240
+ subject: ["bot", "owner", "user", "id"],
1241
+ subjectType: "string",
1242
+ tokenRequest: {
1243
+ authIn: "header",
1244
+ encoding: "application/json",
1245
+ url: "https://api.notion.com/v1/oauth/token"
1246
+ }
1247
+ },
1248
+ okta: {
1249
+ authorizationUrl: (config) => `https://${config.domain}/oauth2/default/v1/authorize`,
1250
+ isOIDC: true,
1251
+ isRefreshable: true,
1252
+ PKCEMethod: "S256",
1253
+ profileRequest: {
1254
+ authIn: "header",
1255
+ encoding: "application/json",
1256
+ method: "GET",
1257
+ url: (config) => `https://${config.domain}/oauth2/default/v1/userinfo`
1258
+ },
1259
+ revocationRequest: {
1260
+ authIn: "body",
1261
+ encoding: "application/json",
1262
+ tokenParamName: "token",
1263
+ url: (config) => `https://${config.domain}/oauth2/default/v1/revoke`
1264
+ },
1265
+ scopeRequired: true,
1266
+ subject: ["id"],
1267
+ subjectType: "string",
1268
+ tokenRequest: {
1269
+ authIn: "body",
1270
+ encoding: "application/x-www-form-urlencoded",
1271
+ url: (config) => `https://${config.domain}/oauth2/default/v1/token`
1272
+ }
1273
+ },
1274
+ onspark: {
1275
+ authorizationUrl: "https://onspark.com/oauth2/authorize",
1276
+ email: ["email"],
1277
+ familyName: ["family_name"],
1278
+ fullName: ["name"],
1279
+ givenName: ["given_name"],
1280
+ isOIDC: true,
1281
+ isRefreshable: true,
1282
+ picture: ["picture"],
1283
+ PKCEMethod: "S256",
1284
+ profileRequest: {
1285
+ authIn: "header",
1286
+ encoding: "application/json",
1287
+ method: "GET",
1288
+ url: "https://onspark.com/oauth2/userinfo"
1289
+ },
1290
+ revocationRequest: {
1291
+ authIn: "body",
1292
+ encoding: "application/x-www-form-urlencoded",
1293
+ tokenParamName: "token",
1294
+ url: "https://onspark.com/oauth2/revoke"
1295
+ },
1296
+ scopeRequired: true,
1297
+ subject: ["sub"],
1298
+ subjectType: "string",
1299
+ tokenRequest: {
1300
+ authIn: "body",
1301
+ encoding: "application/x-www-form-urlencoded",
1302
+ url: "https://onspark.com/oauth2/token"
1303
+ }
1304
+ },
1305
+ osu: {
1306
+ authorizationUrl: "https://osu.ppy.sh/oauth/authorize",
1307
+ isOIDC: false,
1308
+ isRefreshable: true,
1309
+ picture: ["avatar_url"],
1310
+ profileRequest: {
1311
+ authIn: "header",
1312
+ encoding: "application/json",
1313
+ method: "GET",
1314
+ url: "https://osu.ppy.sh/api/v2/me"
1315
+ },
1316
+ scopeRequired: false,
1317
+ subject: ["id"],
1318
+ subjectType: "number",
1319
+ tokenRequest: {
1320
+ authIn: "body",
1321
+ encoding: "application/x-www-form-urlencoded",
1322
+ url: "https://osu.ppy.sh/oauth/token"
1323
+ }
1324
+ },
1325
+ patreon: {
1326
+ authorizationUrl: "https://www.patreon.com/oauth2/authorize",
1327
+ isOIDC: false,
1328
+ isRefreshable: true,
1329
+ profileRequest: {
1330
+ authIn: "header",
1331
+ encoding: "application/json",
1332
+ method: "GET",
1333
+ url: "https://www.patreon.com/api/oauth2/v2/identity"
1334
+ },
1335
+ scopeRequired: false,
1336
+ subject: ["data", "id"],
1337
+ subjectType: "string",
1338
+ tokenRequest: {
1339
+ authIn: "body",
1340
+ encoding: "application/x-www-form-urlencoded",
1341
+ url: "https://www.patreon.com/api/oauth2/token"
1342
+ }
1343
+ },
1344
+ pipedrive: {
1345
+ authorizationUrl: "https://oauth.pipedrive.com/oauth/authorize",
1346
+ isOIDC: false,
1347
+ isRefreshable: true,
1348
+ profileRequest: {
1349
+ authIn: "header",
1350
+ encoding: "application/json",
1351
+ method: "GET",
1352
+ url: "https://api.pipedrive.com/v1/users/me"
1353
+ },
1354
+ scopeRequired: true,
1355
+ subject: ["data", "id"],
1356
+ subjectType: "number",
1357
+ tokenRequest: {
1358
+ authIn: "body",
1359
+ encoding: "application/x-www-form-urlencoded",
1360
+ url: "https://oauth.pipedrive.com/oauth/token"
1361
+ }
1362
+ },
1363
+ polar: {
1364
+ authorizationUrl: "https://polar.sh/oauth2/authorize",
1365
+ isOIDC: true,
1366
+ isRefreshable: true,
1367
+ PKCEMethod: "S256",
1368
+ profileRequest: {
1369
+ authIn: "header",
1370
+ encoding: "application/json",
1371
+ method: "GET",
1372
+ url: "https://api.polar.sh/v1/oauth2/userinfo"
1373
+ },
1374
+ revocationRequest: {
1375
+ authIn: "body",
1376
+ encoding: "application/json",
1377
+ tokenParamName: "token",
1378
+ url: "https://api.polar.sh/v1/oauth2/revoke"
1379
+ },
1380
+ scopeRequired: true,
1381
+ subject: ["id"],
1382
+ subjectType: "string",
1383
+ tokenRequest: {
1384
+ authIn: "body",
1385
+ encoding: "application/x-www-form-urlencoded",
1386
+ url: "https://api.polar.sh/v1/oauth2/token"
1387
+ }
1388
+ },
1389
+ polaraccesslink: {
1390
+ authorizationUrl: "https://flow.polar.com/oauth2/authorization",
1391
+ isOIDC: false,
1392
+ isRefreshable: false,
1393
+ PKCEMethod: "S256",
1394
+ profileRequest: {
1395
+ authIn: "header",
1396
+ encoding: "application/json",
1397
+ method: "GET",
1398
+ url: "https://www.polaraccesslink.com/v3/users/me"
1399
+ },
1400
+ scopeRequired: false,
1401
+ subject: ["x_user_id"],
1402
+ subjectType: "number",
1403
+ tokenRequest: {
1404
+ authIn: "header",
1405
+ encoding: "application/x-www-form-urlencoded",
1406
+ url: "https://polarremote.com/v2/oauth2/token"
1407
+ }
1408
+ },
1409
+ polarteampro: {
1410
+ authorizationUrl: "https://auth.polar.com/oauth/authorize",
1411
+ isOIDC: false,
1412
+ isRefreshable: true,
1413
+ PKCEMethod: "S256",
1414
+ profileRequest: {
1415
+ authIn: "header",
1416
+ encoding: "application/json",
1417
+ method: "GET",
1418
+ url: "https://www.polaraccesslink.com/v3/users/<USER_ID>"
1419
+ },
1420
+ scopeRequired: false,
1421
+ subject: ["x_user_id"],
1422
+ subjectType: "number",
1423
+ tokenRequest: {
1424
+ authIn: "header",
1425
+ encoding: "application/x-www-form-urlencoded",
1426
+ url: "https://auth.polar.com/oauth/token"
1427
+ }
1428
+ },
1429
+ reddit: {
1430
+ authorizationUrl: "https://www.reddit.com/api/v1/authorize",
1431
+ isOIDC: false,
1432
+ isRefreshable: true,
1433
+ profileRequest: {
1434
+ authIn: "header",
1435
+ encoding: "application/json",
1436
+ method: "GET",
1437
+ url: "https://oauth.reddit.com/api/v1/me"
1438
+ },
1439
+ revocationRequest: {
1440
+ authIn: "header",
1441
+ body: new URLSearchParams({
1442
+ token_type_hint: "refresh_token"
1443
+ }),
1444
+ encoding: "application/json",
1445
+ url: "https://www.reddit.com/api/v1/revoke_token"
1446
+ },
1447
+ scopeRequired: true,
1448
+ subject: ["id"],
1449
+ subjectType: "string",
1450
+ tokenRequest: {
1451
+ authIn: "header",
1452
+ encoding: "application/x-www-form-urlencoded",
1453
+ url: "https://www.reddit.com/api/v1/access_token"
1454
+ }
1455
+ },
1456
+ roblox: {
1457
+ authorizationUrl: "https://apis.roblox.com/oauth/v1/authorize",
1458
+ isOIDC: true,
1459
+ isRefreshable: true,
1460
+ picture: ["picture"],
1461
+ PKCEMethod: "S256",
1462
+ profileRequest: {
1463
+ authIn: "header",
1464
+ encoding: "application/json",
1465
+ method: "GET",
1466
+ url: "https://apis.roblox.com/oauth/v1/userinfo"
1467
+ },
1468
+ scopeRequired: true,
1469
+ subject: ["id"],
1470
+ subjectType: "string",
1471
+ tokenRequest: {
1472
+ authIn: "body",
1473
+ encoding: "application/x-www-form-urlencoded",
1474
+ url: "https://apis.roblox.com/oauth/v1/token"
1475
+ }
1476
+ },
1477
+ salesforce: {
1478
+ authorizationUrl: "https://login.salesforce.com/services/oauth2/authorize",
1479
+ isOIDC: true,
1480
+ isRefreshable: true,
1481
+ PKCEMethod: "S256",
1482
+ profileRequest: {
1483
+ authIn: "header",
1484
+ encoding: "application/json",
1485
+ method: "GET",
1486
+ url: "https://login.salesforce.com/services/oauth2/userinfo"
1487
+ },
1488
+ revocationRequest: {
1489
+ authIn: "header",
1490
+ encoding: "application/json",
1491
+ url: "https://login.salesforce.com/services/oauth2/revoke"
1492
+ },
1493
+ scopeRequired: false,
1494
+ subject: ["id"],
1495
+ subjectType: "string",
1496
+ tokenRequest: {
1497
+ authIn: "body",
1498
+ encoding: "application/x-www-form-urlencoded",
1499
+ url: "https://login.salesforce.com/services/oauth2/token"
1500
+ }
1501
+ },
1502
+ shikimori: {
1503
+ authorizationUrl: "https://shikimori.org/oauth/authorize",
1504
+ isOIDC: false,
1505
+ isRefreshable: true,
1506
+ profileRequest: {
1507
+ authIn: "header",
1508
+ encoding: "application/json",
1509
+ method: "GET",
1510
+ url: "https://shikimori.one/api/users/whoami"
1511
+ },
1512
+ scopeRequired: false,
1513
+ subject: ["id"],
1514
+ subjectType: "number",
1515
+ tokenRequest: {
1516
+ authIn: "body",
1517
+ encoding: "application/x-www-form-urlencoded",
1518
+ url: "https://shikimori.org/oauth/token"
1519
+ }
1520
+ },
1521
+ slack: {
1522
+ authorizationUrl: "https://slack.com/openid/connect/authorize",
1523
+ isOIDC: true,
1524
+ isRefreshable: true,
1525
+ profileRequest: {
1526
+ authIn: "query",
1527
+ encoding: "application/json",
1528
+ method: "GET",
1529
+ url: "https://slack.com/api/users.identity"
1530
+ },
1531
+ revocationRequest: {
1532
+ authIn: "body",
1533
+ encoding: "application/json",
1534
+ tokenParamName: "token",
1535
+ url: "https://slack.com/api/auth.revoke"
1536
+ },
1537
+ scopeRequired: true,
1538
+ subject: ["id"],
1539
+ subjectType: "string",
1540
+ tokenRequest: {
1541
+ authIn: "body",
1542
+ encoding: "application/x-www-form-urlencoded",
1543
+ url: "https://slack.com/api/openid.connect.token"
1544
+ }
1545
+ },
1546
+ slackuser: {
1547
+ accessTokenPath: ["authed_user", "access_token"],
1548
+ authorizationUrl: "https://slack.com/oauth/v2/authorize",
1549
+ isOIDC: false,
1550
+ isRefreshable: false,
1551
+ profileRequest: {
1552
+ authIn: "header",
1553
+ encoding: "application/json",
1554
+ method: "POST",
1555
+ url: "https://slack.com/api/auth.test"
1556
+ },
1557
+ revocationRequest: {
1558
+ authIn: "body",
1559
+ encoding: "application/json",
1560
+ tokenParamName: "token",
1561
+ url: "https://slack.com/api/auth.revoke"
1562
+ },
1563
+ scopeParamName: "user_scope",
1564
+ scopeRequired: true,
1565
+ subject: ["user_id"],
1566
+ subjectType: "string",
1567
+ tokenRequest: {
1568
+ authIn: "body",
1569
+ encoding: "application/x-www-form-urlencoded",
1570
+ url: "https://slack.com/api/oauth.v2.access"
1571
+ }
1572
+ },
1573
+ spotify: {
1574
+ authorizationUrl: "https://accounts.spotify.com/authorize",
1575
+ isOIDC: false,
1576
+ isRefreshable: true,
1577
+ PKCEMethod: "S256",
1578
+ profileRequest: {
1579
+ authIn: "header",
1580
+ encoding: "application/json",
1581
+ method: "GET",
1582
+ url: "https://api.spotify.com/v1/me"
1583
+ },
1584
+ scopeRequired: false,
1585
+ subject: ["id"],
1586
+ subjectType: "string",
1587
+ tokenRequest: {
1588
+ authIn: "body",
1589
+ encoding: "application/x-www-form-urlencoded",
1590
+ url: "https://accounts.spotify.com/api/token"
1591
+ }
1592
+ },
1593
+ startgg: {
1594
+ authorizationUrl: "https://start.gg/oauth/authorize",
1595
+ email: ["data", "currentUser", "email"],
1596
+ isOIDC: false,
1597
+ isRefreshable: true,
1598
+ profileRequest: {
1599
+ authIn: "header",
1600
+ body: {
1601
+ query: `query { currentUser { id slug email player { gamerTag } } }`
1602
+ },
1603
+ encoding: "application/json",
1604
+ headers: {
1605
+ Accept: "application/json",
1606
+ "Content-Type": "application/json"
1607
+ },
1608
+ method: "POST",
1609
+ url: "https://api.start.gg/gql/alpha"
1610
+ },
1611
+ scopeRequired: false,
1612
+ subject: ["data", "currentUser", "id"],
1613
+ subjectType: "number",
1614
+ tokenRequest: {
1615
+ authIn: "body",
1616
+ encoding: "application/x-www-form-urlencoded",
1617
+ url: "https://api.start.gg/oauth/access_token"
1618
+ }
1619
+ },
1620
+ strava: {
1621
+ authorizationUrl: "https://www.strava.com/oauth/authorize",
1622
+ familyName: ["lastname"],
1623
+ givenName: ["firstname"],
1624
+ isOIDC: false,
1625
+ isRefreshable: true,
1626
+ picture: ["profile"],
1627
+ PKCEMethod: "S256",
1628
+ profileRequest: {
1629
+ authIn: "header",
1630
+ encoding: "application/json",
1631
+ method: "GET",
1632
+ url: "https://www.strava.com/api/v3/athlete"
1633
+ },
1634
+ revocationRequest: {
1635
+ authIn: "query",
1636
+ body: new URLSearchParams({
1637
+ token_type_hint: "access_token"
1638
+ }),
1639
+ encoding: "application/json",
1640
+ tokenParamName: "access_token",
1641
+ url: "https://www.strava.com/oauth/deauthorize"
1642
+ },
1643
+ scopeRequired: false,
1644
+ subject: ["id"],
1645
+ subjectType: "number",
1646
+ tokenRequest: {
1647
+ authIn: "body",
1648
+ encoding: "application/x-www-form-urlencoded",
1649
+ url: "https://www.strava.com/oauth/token"
1650
+ }
1651
+ },
1652
+ synology: {
1653
+ authorizationUrl: (config) => `${config.baseURL}/webman/sso/SSOOauth.cgi?client_id=${config.clientId}&response_type=code&redirect_uri=${config.redirectUri}`,
1654
+ isOIDC: false,
1655
+ isRefreshable: false,
1656
+ profileRequest: {
1657
+ authIn: "header",
1658
+ encoding: "application/json",
1659
+ method: "GET",
1660
+ url: (config) => `${config.baseURL}/webman/sso/SSOUserInfo.cgi?client_id=${config.clientId}&access_token=${config.accessToken}`
1661
+ },
1662
+ scopeRequired: false,
1663
+ subject: ["data", "id"],
1664
+ subjectType: "number",
1665
+ tokenRequest: {
1666
+ authIn: "body",
1667
+ encoding: "application/x-www-form-urlencoded",
1668
+ url: (config) => `${config.baseURL}/webman/sso/SSOAccessToken.cgi?client_id=${config.clientId}&client_secret=${config.clientSecret}`
1669
+ }
1670
+ },
1671
+ tiktok: {
1672
+ authorizationUrl: "https://www.tiktok.com/v2/auth/authorize",
1673
+ createAuthorizationURLSearchParams: (config) => ({
1674
+ client_key: config.clientId
1675
+ }),
1676
+ isOIDC: false,
1677
+ isRefreshable: true,
1678
+ PKCEMethod: "S256",
1679
+ profileRequest: {
1680
+ authIn: "query",
1681
+ encoding: "application/json",
1682
+ method: "GET",
1683
+ url: "https://open.douyin.com/oauth/userinfo"
1684
+ },
1685
+ revocationRequest: {
1686
+ authIn: "body",
1687
+ encoding: "application/json",
1688
+ tokenParamName: "token",
1689
+ url: "https://open.tiktokapis.com/v2/oauth/revoke/"
1690
+ },
1691
+ scopeRequired: false,
1692
+ subject: ["data", "open_id"],
1693
+ subjectType: "string",
1694
+ tokenRequest: {
1695
+ authIn: "body",
1696
+ encoding: "application/x-www-form-urlencoded",
1697
+ url: "https://open.tiktokapis.com/v2/oauth/token/"
1698
+ }
1699
+ },
1700
+ tiltify: {
1701
+ authorizationUrl: "https://v5api.tiltify.com/oauth/authorize",
1702
+ isOIDC: false,
1703
+ isRefreshable: true,
1704
+ profileRequest: {
1705
+ authIn: "header",
1706
+ encoding: "application/json",
1707
+ method: "GET",
1708
+ url: "https://v5api.tiltify.com/api/public/current-user"
1709
+ },
1710
+ scopeRequired: false,
1711
+ subject: ["data", "id"],
1712
+ subjectType: "string",
1713
+ tokenRequest: {
1714
+ authIn: "body",
1715
+ encoding: "application/x-www-form-urlencoded",
1716
+ url: "https://v5api.tiltify.com/oauth/token"
1717
+ }
1718
+ },
1719
+ tumblr: {
1720
+ authorizationUrl: "https://www.tumblr.com/oauth2/authorize",
1721
+ isOIDC: false,
1722
+ isRefreshable: true,
1723
+ profileRequest: {
1724
+ authIn: "header",
1725
+ encoding: "application/json",
1726
+ method: "GET",
1727
+ url: "https://api.tumblr.com/v2/user/info"
1728
+ },
1729
+ scopeRequired: false,
1730
+ subject: ["response", "user", "name"],
1731
+ subjectType: "string",
1732
+ tokenRequest: {
1733
+ authIn: "body",
1734
+ encoding: "application/x-www-form-urlencoded",
1735
+ url: "https://api.tumblr.com/v2/oauth2/token"
1736
+ }
1737
+ },
1738
+ twitch: {
1739
+ authorizationUrl: "https://id.twitch.tv/oauth2/authorize",
1740
+ isOIDC: true,
1741
+ isRefreshable: true,
1742
+ profileRequest: {
1743
+ authIn: "header",
1744
+ encoding: "application/json",
1745
+ headers: (config) => ({
1746
+ "Client-Id": config.clientId
1747
+ }),
1748
+ method: "GET",
1749
+ url: "https://api.twitch.tv/helix/users"
1750
+ },
1751
+ revocationRequest: {
1752
+ authIn: "query",
1753
+ encoding: "application/json",
1754
+ headers: (config) => ({
1755
+ "Client-Id": config.clientId
1756
+ }),
1757
+ tokenParamName: "token",
1758
+ url: "https://id.twitch.tv/oauth2/revoke"
1759
+ },
1760
+ scopeRequired: false,
1761
+ subject: ["id"],
1762
+ subjectType: "string",
1763
+ tokenRequest: {
1764
+ authIn: "body",
1765
+ encoding: "application/x-www-form-urlencoded",
1766
+ url: "https://id.twitch.tv/oauth2/token"
1767
+ }
1768
+ },
1769
+ twitter: {
1770
+ authorizationUrl: "https://twitter.com/i/oauth2/authorize",
1771
+ isOIDC: false,
1772
+ isRefreshable: true,
1773
+ PKCEMethod: "S256",
1774
+ profileRequest: {
1775
+ authIn: "header",
1776
+ encoding: "application/json",
1777
+ method: "GET",
1778
+ url: "https://api.twitter.com/2/users/me"
1779
+ },
1780
+ revocationRequest: {
1781
+ authIn: "header",
1782
+ encoding: "application/json",
1783
+ url: "https://api.twitter.com/2/oauth2/revoke"
1784
+ },
1785
+ scopeRequired: false,
1786
+ subject: ["data", "id"],
1787
+ subjectType: "number",
1788
+ tokenRequest: {
1789
+ authIn: "body",
1790
+ encoding: "application/x-www-form-urlencoded",
1791
+ url: "https://api.twitter.com/2/oauth2/token"
1792
+ }
1793
+ },
1794
+ vk: {
1795
+ authorizationUrl: "https://oauth.vk.com/authorize",
1796
+ isOIDC: false,
1797
+ isRefreshable: false,
1798
+ profileRequest: {
1799
+ authIn: "query",
1800
+ encoding: "application/json",
1801
+ method: "GET",
1802
+ url: "https://api.vk.com/method/users.get"
1803
+ },
1804
+ scopeRequired: false,
1805
+ subject: ["response", "0", "id"],
1806
+ subjectType: "number",
1807
+ tokenRequest: {
1808
+ authIn: "body",
1809
+ encoding: "application/x-www-form-urlencoded",
1810
+ url: "https://oauth.vk.com/access_token"
1811
+ }
1812
+ },
1813
+ withings: {
1814
+ accessTokenPath: ["body", "access_token"],
1815
+ authorizationUrl: "https://account.withings.com/oauth2_user/authorize2",
1816
+ isOIDC: false,
1817
+ isRefreshable: true,
1818
+ profileRequest: {
1819
+ authIn: "header",
1820
+ body: async (config) => {
1821
+ const props = await getWithingsProps(config);
1822
+ if (props === undefined)
1823
+ throw new Error("Failed to get Withings search properties");
1824
+ const { nonce, hashedSignature } = props;
1825
+ return [
1826
+ ["action", "getuser"],
1827
+ ["nonce", nonce],
1828
+ ["client_id", config.clientId],
1829
+ ["signature", hashedSignature]
1830
+ ];
1831
+ },
1832
+ encoding: "application/x-www-form-urlencoded",
1833
+ method: "POST",
1834
+ url: "https://wbsapi.withings.net/v2/oauth2"
1835
+ },
1836
+ refreshAccessTokenBody: {
1837
+ action: "requesttoken"
1838
+ },
1839
+ revocationRequest: {
1840
+ authIn: "header",
1841
+ body: async (config) => {
1842
+ const props = await getWithingsProps(config);
1843
+ if (!props)
1844
+ throw new Error("Failed to get Withings props");
1845
+ const { nonce, hashedSignature } = props;
1846
+ return [
1847
+ ["action", "revoke"],
1848
+ ["client_id", config.clientId],
1849
+ ["nonce", nonce],
1850
+ ["signature", hashedSignature]
1851
+ ];
1852
+ },
1853
+ encoding: "application/x-www-form-urlencoded",
1854
+ method: "POST",
1855
+ url: "https://wbsapi.withings.net/v2/oauth2"
1856
+ },
1857
+ scopeDelimiter: ",",
1858
+ scopeRequired: true,
1859
+ subject: ["userid"],
1860
+ subjectType: "string",
1861
+ tokenRequest: {
1862
+ authIn: "body",
1863
+ encoding: "application/x-www-form-urlencoded",
1864
+ url: "https://wbsapi.withings.net/v2/oauth2"
1865
+ },
1866
+ validateAuthorizationCodeBody: {
1867
+ action: "requesttoken"
1868
+ }
1869
+ },
1870
+ workos: {
1871
+ authorizationUrl: (config) => `https://${config.domain}/oauth2/authorize`,
1872
+ createAuthorizationURLSearchParams: () => {
1873
+ const nonce = crypto.randomUUID();
1874
+ return {
1875
+ nonce
1876
+ };
1877
+ },
1878
+ email: ["email"],
1879
+ familyName: ["family_name"],
1880
+ fullName: ["name"],
1881
+ givenName: ["given_name"],
1882
+ isOIDC: true,
1883
+ isRefreshable: true,
1884
+ PKCEMethod: "S256",
1885
+ profileRequest: {
1886
+ authIn: "header",
1887
+ encoding: "application/json",
1888
+ method: "POST",
1889
+ url: (config) => `https://${config.domain}/oauth2/userinfo`
1890
+ },
1891
+ scopeRequired: false,
1892
+ subject: ["id"],
1893
+ subjectType: "string",
1894
+ tokenRequest: {
1895
+ authIn: "body",
1896
+ encoding: "application/x-www-form-urlencoded",
1897
+ url: (config) => `https://${config.domain}/oauth2/token`
1898
+ }
1899
+ },
1900
+ yahoo: {
1901
+ authorizationUrl: "https://api.login.yahoo.com/oauth2/request_auth",
1902
+ isOIDC: true,
1903
+ isRefreshable: true,
1904
+ PKCEMethod: "S256",
1905
+ profileRequest: {
1906
+ authIn: "header",
1907
+ encoding: "application/json",
1908
+ method: "GET",
1909
+ url: "https://api.login.yahoo.com/openid/v1/userinfo"
1910
+ },
1911
+ revocationRequest: {
1912
+ authIn: "header",
1913
+ encoding: "application/json",
1914
+ url: "https://api.login.yahoo.com/oauth2/revoke"
1915
+ },
1916
+ scopeRequired: false,
1917
+ subject: ["id"],
1918
+ subjectType: "string",
1919
+ tokenRequest: {
1920
+ authIn: "body",
1921
+ encoding: "application/x-www-form-urlencoded",
1922
+ url: "https://api.login.yahoo.com/oauth2/get_token"
1923
+ }
1924
+ },
1925
+ yandex: {
1926
+ authorizationUrl: "https://oauth.yandex.com/authorize",
1927
+ createAuthorizationURLSearchParams: {
1928
+ device_id: crypto.randomUUID(),
1929
+ device_name: `${navigator.platform ?? "Unknown"} \u2014 ${(navigator.userAgent.split(")")[0] || "").split("(").pop() || "Unknown"}`
1930
+ },
1931
+ email: ["default_email"],
1932
+ familyName: ["last_name"],
1933
+ fullName: ["real_name"],
1934
+ givenName: ["first_name"],
1935
+ isOIDC: false,
1936
+ isRefreshable: true,
1937
+ PKCEMethod: "S256",
1938
+ profileRequest: {
1939
+ authIn: "header",
1940
+ encoding: "application/json",
1941
+ method: "GET",
1942
+ url: "https://login.yandex.ru/info"
1943
+ },
1944
+ revocationRequest: {
1945
+ authIn: "body",
1946
+ encoding: "application/json",
1947
+ tokenParamName: "access_token",
1948
+ url: "https://oauth.yandex.com/revoke_token"
1949
+ },
1950
+ scopeRequired: false,
1951
+ subject: ["id"],
1952
+ subjectType: "string",
1953
+ tokenRequest: {
1954
+ authIn: "body",
1955
+ encoding: "application/x-www-form-urlencoded",
1956
+ url: "https://oauth.yandex.com/token"
1957
+ }
1958
+ },
1959
+ zoho: {
1960
+ authorizationUrl: (config) => `https://accounts.zoho.${config.region ?? "com"}/oauth/v2/auth`,
1961
+ isOIDC: false,
1962
+ isRefreshable: true,
1963
+ PKCEMethod: "S256",
1964
+ profileRequest: {
1965
+ authIn: "header",
1966
+ encoding: "application/json",
1967
+ method: "GET",
1968
+ url: (config) => `https://accounts.zoho.${config.region ?? "com"}/oauth/user/info`
1969
+ },
1970
+ revocationRequest: {
1971
+ authIn: "query",
1972
+ encoding: "application/x-www-form-urlencoded",
1973
+ tokenParamName: "token",
1974
+ url: (config) => `https://accounts.zoho.${config.region ?? "com"}/oauth/v2/token/revoke`
1975
+ },
1976
+ scopeRequired: true,
1977
+ subject: ["ZUID"],
1978
+ subjectType: "string",
1979
+ tokenRequest: {
1980
+ authIn: "body",
1981
+ encoding: "application/x-www-form-urlencoded",
1982
+ url: (config) => `https://accounts.zoho.${config.region ?? "com"}/oauth/v2/token`
1983
+ }
1984
+ },
1985
+ zoom: {
1986
+ authorizationUrl: "https://zoom.us/oauth/authorize",
1987
+ email: ["email"],
1988
+ familyName: ["last_name"],
1989
+ givenName: ["first_name"],
1990
+ isOIDC: false,
1991
+ isRefreshable: true,
1992
+ picture: ["pic_url"],
1993
+ PKCEMethod: "S256",
1994
+ profileRequest: {
1995
+ authIn: "header",
1996
+ encoding: "application/json",
1997
+ method: "GET",
1998
+ url: "https://api.zoom.us/v2/users/me"
1999
+ },
2000
+ revocationRequest: {
2001
+ authIn: "query",
2002
+ encoding: "application/json",
2003
+ headers: (config) => ({
2004
+ Authorization: `Basic ${btoa(`${config.clientId}:${config.clientSecret}`)}`
2005
+ }),
2006
+ tokenParamName: "token",
2007
+ url: "https://zoom.us/oauth/revoke"
2008
+ },
2009
+ scopeRequired: false,
2010
+ subject: ["id"],
2011
+ subjectType: "string",
2012
+ tokenRequest: {
2013
+ authIn: "body",
2014
+ encoding: "application/x-www-form-urlencoded",
2015
+ url: "https://zoom.us/oauth/token"
2016
+ }
2017
+ }
2018
+ });
2019
+ var hasClientSecret = (credentials) => {
2020
+ if (typeof credentials !== "object" || credentials === null)
2021
+ return false;
2022
+ const secret = Reflect.get(credentials, "clientSecret");
2023
+ return typeof secret === "string";
2024
+ };
2025
+ var isExpectedType = (value, kind) => {
2026
+ switch (kind) {
2027
+ case "string":
2028
+ return typeof value === "string";
2029
+ case "number":
2030
+ return typeof value === "number";
2031
+ case "boolean":
2032
+ return typeof value === "boolean";
2033
+ case "object":
2034
+ return typeof value === "object" && value !== null;
2035
+ default:
2036
+ return false;
2037
+ }
2038
+ };
2039
+ var isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
2040
+ var isOIDCProviderOption = (option) => {
2041
+ if (!isValidProviderOption(option))
2042
+ return false;
2043
+ const provider = providers[option];
2044
+ return provider.isOIDC;
2045
+ };
2046
+ var isPKCEProviderOption = (option) => {
2047
+ if (!isValidProviderOption(option))
2048
+ return false;
2049
+ const provider = providers[option];
2050
+ return provider.PKCEMethod !== undefined;
2051
+ };
2052
+ var isRefreshableOAuth2Client = (providerName, _client) => isRefreshableProviderOption(providerName);
2053
+ var isRefreshableProviderOption = (option) => {
2054
+ if (!isValidProviderOption(option))
2055
+ return false;
2056
+ const provider = providers[option];
2057
+ return provider.isRefreshable;
2058
+ };
2059
+ var isRevocableOAuth2Client = (providerName, _client) => isRevocableProviderOption(providerName);
2060
+ var isRevocableProviderOption = (option) => {
2061
+ if (!isValidProviderOption(option))
2062
+ return false;
2063
+ const provider = providers[option];
2064
+ return provider.revocationRequest !== undefined;
2065
+ };
2066
+ var isScopeRequiredProviderOption = (option) => {
2067
+ if (!isValidProviderOption(option))
2068
+ return false;
2069
+ const provider = providers[option];
2070
+ return provider.scopeRequired;
2071
+ };
2072
+ var isValidProviderOption = (option) => Object.hasOwn(providers, option);
2073
+ var createOAuth2FetchError = async (response) => {
2074
+ const clone = response.clone();
2075
+ const prefix = `HTTP ${response.status} ${response.statusText} for ${response.url}`;
2076
+ const payload = await response.json().catch(() => null);
2077
+ if (payload && typeof payload === "object" && Object.keys(payload).length) {
2078
+ return new Error(`${prefix}
2079
+ ${JSON.stringify(payload)}`);
2080
+ }
2081
+ const text = await clone.text().catch(() => "");
2082
+ if (text) {
2083
+ return new Error(`${prefix}
2084
+ ${text}`);
2085
+ }
2086
+ return new Error(prefix);
2087
+ };
2088
+ var createOAuth2Request = ({
2089
+ url,
2090
+ body,
2091
+ authIn,
2092
+ headers,
2093
+ encoding,
2094
+ clientId,
2095
+ clientSecret
2096
+ }) => {
2097
+ const oauthHeaders = new Headers(headers);
2098
+ oauthHeaders.set("Accept", "application/json");
2099
+ oauthHeaders.set("User-Agent", "citra");
2100
+ if (authIn === "header") {
2101
+ if (!clientSecret) {
2102
+ throw new Error("clientSecret required for header auth");
2103
+ }
2104
+ oauthHeaders.set("Authorization", `Basic ${encodeBase64(`${clientId}:${clientSecret}`)}`);
2105
+ }
2106
+ if (encoding === "application/json") {
2107
+ oauthHeaders.set("Content-Type", "application/json");
2108
+ return new Request(url, {
2109
+ body: JSON.stringify(body),
2110
+ headers: oauthHeaders,
2111
+ method: "POST"
2112
+ });
2113
+ }
2114
+ oauthHeaders.set("Content-Type", "application/x-www-form-urlencoded");
2115
+ const entries = body instanceof URLSearchParams ? Array.from(body.entries()) : Object.entries(body).filter((entry) => typeof entry[1] === "string");
2116
+ const params = new URLSearchParams(entries);
2117
+ if (authIn === "body") {
2118
+ params.set("client_id", clientId);
2119
+ clientSecret && params.set("client_secret", clientSecret);
2120
+ }
2121
+ return new Request(url, {
2122
+ body: params.toString(),
2123
+ headers: oauthHeaders,
2124
+ method: "POST"
2125
+ });
2126
+ };
2127
+ var decodeBase64 = (input, toUint8Array = false) => {
2128
+ const b64 = input.replace(/-/g, "+").replace(/_/g, "/") + "==".slice(0, (BASE64_BLOCK_SIZE - input.length % BASE64_BLOCK_SIZE) % BASE64_BLOCK_SIZE);
2129
+ const raw = atob(b64);
2130
+ if (!toUint8Array) {
2131
+ return raw;
2132
+ }
2133
+ const bytes = new Uint8Array(raw.length);
2134
+ for (let i = 0;i < raw.length; i++) {
2135
+ bytes[i] = raw.charCodeAt(i);
2136
+ }
2137
+ return bytes;
2138
+ };
2139
+ var decodeJWT = (tokenString) => {
2140
+ const [headerSegment, payloadSegment, signatureSegment] = tokenString.split(".");
2141
+ if (!headerSegment || !payloadSegment || !signatureSegment) {
2142
+ throw new Error("Invalid JWT format");
2143
+ }
2144
+ const decodedPayload = decodeBase64(payloadSegment);
2145
+ if (typeof decodedPayload !== "string") {
2146
+ throw new Error("Expected JWT payload to be a UTF-8 string");
2147
+ }
2148
+ const claims = JSON.parse(decodedPayload);
2149
+ return claims;
2150
+ };
2151
+ var encodeBase64 = (input) => {
2152
+ let raw;
2153
+ if (typeof input === "string") {
2154
+ raw = input;
2155
+ } else {
2156
+ const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
2157
+ raw = bytes.reduce((acc, byte) => acc + String.fromCharCode(byte), "");
2158
+ }
2159
+ return btoa(raw);
2160
+ };
2161
+ var getWithingsProps = async (config) => {
2162
+ const timestamp = Math.floor(Date.now() / 1000);
2163
+ const signature = `getnonce,${config.clientId},${timestamp}`;
2164
+ const hashedSignature = await hmacSha256(signature, config.clientSecret);
2165
+ const nonceUrl = new URL("https://wbsapi.withings.net/v2/signature");
2166
+ nonceUrl.searchParams.set("action", "getnonce");
2167
+ nonceUrl.searchParams.set("client_id", config.clientId);
2168
+ nonceUrl.searchParams.set("timestamp", timestamp.toString());
2169
+ nonceUrl.searchParams.set("signature", hashedSignature);
2170
+ const nonceTarget = nonceUrl.toString();
2171
+ const nonceResponse = await fetch(nonceTarget, { method: "POST" });
2172
+ const nonceData = await nonceResponse.json();
2173
+ if (nonceData.status === 0) {
2174
+ return {
2175
+ hashedSignature,
2176
+ nonce: nonceData.body.nonce
2177
+ };
2178
+ }
2179
+ return;
2180
+ };
2181
+ var hmacSha256 = async (message, secret) => {
2182
+ const encoder = new TextEncoder;
2183
+ const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
2184
+ const sigBuffer = await crypto.subtle.sign("HMAC", key, encoder.encode(message));
2185
+ return Array.from(new Uint8Array(sigBuffer)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
2186
+ };
2187
+ var extractPropFromIdentity = (identity, keys, propType) => {
2188
+ let value = identity;
2189
+ for (const key of keys) {
2190
+ if (Array.isArray(value))
2191
+ value = value[Number(key)];
2192
+ if (!isObject(value)) {
2193
+ throw new Error(`Invalid identity data shape: expected object, got ${typeof value}`);
2194
+ }
2195
+ value = value[key];
2196
+ }
2197
+ if (propType !== undefined && !isExpectedType(value, propType)) {
2198
+ throw new Error(`Invalid identity data shape: expected ${propType}, got ${typeof value}`);
2199
+ }
2200
+ return value;
2201
+ };
2202
+ var getProviderSubjectKeys = (providerConfiguration, source) => providerConfiguration.subjectBySource?.[source] ?? providerConfiguration.subject;
2203
+ var setPropInIdentity = (identity, keys, value) => {
2204
+ if (keys.length === 0) {
2205
+ return identity;
2206
+ }
2207
+ let cursor = identity;
2208
+ for (const key of keys.slice(0, -1)) {
2209
+ const next = cursor[key];
2210
+ cursor[key] = isObject(next) ? next : {};
2211
+ cursor = cursor[key];
2212
+ }
2213
+ cursor[keys[keys.length - 1]] = value;
2214
+ return identity;
2215
+ };
2216
+ var normalizeProviderIdentity = ({
2217
+ identity,
2218
+ providerConfiguration,
2219
+ source
2220
+ }) => {
2221
+ const sourceKeys = getProviderSubjectKeys(providerConfiguration, source);
2222
+ const canonicalKeys = providerConfiguration.subject;
2223
+ if (sourceKeys.join(".") === canonicalKeys.join(".")) {
2224
+ return identity;
2225
+ }
2226
+ const subject = extractPropFromIdentity(identity, sourceKeys, providerConfiguration.subjectType);
2227
+ const normalizedIdentity = structuredClone(identity);
2228
+ return setPropInIdentity(normalizedIdentity, canonicalKeys, subject);
2229
+ };
2230
+ var createS256CodeChallenge = async (codeVerifier) => {
2231
+ const data = new TextEncoder().encode(codeVerifier);
2232
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
2233
+ return base64Url(hashBuffer);
2234
+ };
2235
+ var createRandomBase64UrlGenerator = (length) => () => {
2236
+ const buffer = crypto.getRandomValues(new Uint8Array(length));
2237
+ return base64Url(buffer);
2238
+ };
2239
+ var generateCodeVerifier = createRandomBase64UrlGenerator(NUM_GENERATOR_BYTES);
2240
+ var generateState = createRandomBase64UrlGenerator(NUM_GENERATOR_BYTES);
2241
+ var base64Url = (input) => encodeBase64(input).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2242
+ var ALG_ES256 = "ES256";
2243
+ var ALG_RS256 = "RS256";
2244
+ var CLOCK_SKEW_SECONDS = 60;
2245
+ var DEFAULT_SCOPES = ["openid", "email", "profile"];
2246
+ var JWKS_REFETCH_COOLDOWN_MS = 60000;
2247
+ var JWT_SEGMENT_COUNT = 3;
2248
+ var MILLISECONDS_PER_SECOND = 1000;
2249
+ var trimTrailingSlash = (value) => value.endsWith("/") ? value.slice(0, -1) : value;
2250
+ var fetchJson = async (url) => {
2251
+ const response = await fetch(url, {
2252
+ headers: { accept: "application/json" }
2253
+ });
2254
+ if (!response.ok) {
2255
+ throw new Error(`Request to ${url} failed with status ${response.status}`);
2256
+ }
2257
+ return response.json();
2258
+ };
2259
+ var decodeJsonSegment = (segment) => {
2260
+ const decoded = decodeBase64(segment);
2261
+ if (typeof decoded !== "string") {
2262
+ throw new Error("Expected a base64url-encoded JWT segment");
2263
+ }
2264
+ const parsed = JSON.parse(decoded);
2265
+ if (typeof parsed !== "object" || parsed === null) {
2266
+ throw new Error("Expected a JWT segment to decode to a JSON object");
2267
+ }
2268
+ return parsed;
2269
+ };
2270
+ var importVerificationKey = (jwk, alg) => {
2271
+ if (alg === ALG_RS256) {
2272
+ return crypto.subtle.importKey("jwk", jwk, { hash: "SHA-256", name: "RSASSA-PKCS1-v1_5" }, false, ["verify"]);
2273
+ }
2274
+ if (alg === ALG_ES256) {
2275
+ return crypto.subtle.importKey("jwk", jwk, { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]);
2276
+ }
2277
+ throw new Error(`Unsupported id_token signing algorithm "${alg}"`);
2278
+ };
2279
+ var verifySignature = (key, alg, signingInput, signature) => {
2280
+ const algorithm = alg === ALG_ES256 ? { hash: "SHA-256", name: "ECDSA" } : { name: "RSASSA-PKCS1-v1_5" };
2281
+ return crypto.subtle.verify(algorithm, key, new Uint8Array(signature), new TextEncoder().encode(signingInput));
2282
+ };
2283
+ var selectKey = (jwks, kid) => jwks.find((jwk) => kid === undefined || jwk.kid === kid);
2284
+ var assertClaims = (payload, expected) => {
2285
+ const aud = Reflect.get(payload, "aud");
2286
+ const exp = Reflect.get(payload, "exp");
2287
+ const iss = Reflect.get(payload, "iss");
2288
+ const sub = Reflect.get(payload, "sub");
2289
+ const audiences = Array.isArray(aud) ? aud : [aud];
2290
+ const nowSeconds = Math.floor(Date.now() / MILLISECONDS_PER_SECOND);
2291
+ if (iss !== expected.issuer) {
2292
+ throw new Error('id_token "iss" does not match the provider issuer');
2293
+ }
2294
+ if (typeof sub !== "string" || sub.length === 0) {
2295
+ throw new Error('id_token is missing "sub"');
2296
+ }
2297
+ if (!audiences.includes(expected.audience)) {
2298
+ throw new Error('id_token "aud" does not include the client id');
2299
+ }
2300
+ if (typeof exp !== "number" || exp + CLOCK_SKEW_SECONDS < nowSeconds) {
2301
+ throw new Error("id_token has expired");
2302
+ }
2303
+ if (expected.nonce !== undefined && Reflect.get(payload, "nonce") !== expected.nonce) {
2304
+ throw new Error('id_token "nonce" does not match');
2305
+ }
2306
+ const claims = { ...payload, aud, exp, iss, sub };
2307
+ return claims;
2308
+ };
2309
+ var verifyIdToken = async ({
2310
+ audience,
2311
+ idToken,
2312
+ issuer,
2313
+ jwks,
2314
+ nonce
2315
+ }) => {
2316
+ const segments = idToken.split(".");
2317
+ const [headerSegment, payloadSegment, signatureSegment] = segments;
2318
+ if (segments.length !== JWT_SEGMENT_COUNT || headerSegment === undefined || payloadSegment === undefined || signatureSegment === undefined) {
2319
+ throw new Error("Invalid id_token: expected three segments");
2320
+ }
2321
+ const header = decodeJsonSegment(headerSegment);
2322
+ const alg = Reflect.get(header, "alg");
2323
+ const kid = Reflect.get(header, "kid");
2324
+ if (typeof alg !== "string") {
2325
+ throw new Error('id_token header is missing "alg"');
2326
+ }
2327
+ const jwk = selectKey(jwks, typeof kid === "string" ? kid : undefined);
2328
+ if (jwk === undefined) {
2329
+ throw new Error('No JWKS key matches the id_token "kid"');
2330
+ }
2331
+ const key = await importVerificationKey(jwk, alg);
2332
+ const signature = decodeBase64(signatureSegment, true);
2333
+ if (typeof signature === "string") {
2334
+ throw new Error("Failed to decode the id_token signature");
2335
+ }
2336
+ const isValid = await verifySignature(key, alg, `${headerSegment}.${payloadSegment}`, signature);
2337
+ if (!isValid) {
2338
+ throw new Error("id_token signature verification failed");
2339
+ }
2340
+ return assertClaims(decodeJsonSegment(payloadSegment), {
2341
+ audience,
2342
+ issuer,
2343
+ nonce
2344
+ });
2345
+ };
2346
+ var toDiscoveryDocument = (value, expectedIssuer) => {
2347
+ if (typeof value !== "object" || value === null) {
2348
+ throw new Error("OIDC discovery document is not a JSON object");
2349
+ }
2350
+ const issuer = Reflect.get(value, "issuer");
2351
+ const authorizationEndpoint = Reflect.get(value, "authorization_endpoint");
2352
+ const tokenEndpoint = Reflect.get(value, "token_endpoint");
2353
+ const jwksUri = Reflect.get(value, "jwks_uri");
2354
+ const userinfoEndpoint = Reflect.get(value, "userinfo_endpoint");
2355
+ if (typeof issuer !== "string" || typeof authorizationEndpoint !== "string" || typeof tokenEndpoint !== "string" || typeof jwksUri !== "string") {
2356
+ throw new Error("OIDC discovery document is missing required endpoints");
2357
+ }
2358
+ if (trimTrailingSlash(issuer) !== trimTrailingSlash(expectedIssuer)) {
2359
+ throw new Error(`OIDC discovery issuer "${issuer}" does not match configured issuer "${expectedIssuer}"`);
2360
+ }
2361
+ return {
2362
+ authorization_endpoint: authorizationEndpoint,
2363
+ issuer,
2364
+ jwks_uri: jwksUri,
2365
+ token_endpoint: tokenEndpoint,
2366
+ userinfo_endpoint: typeof userinfoEndpoint === "string" ? userinfoEndpoint : undefined
2367
+ };
2368
+ };
2369
+ var fetchDiscoveryDocument = async (issuer) => {
2370
+ const base = trimTrailingSlash(issuer);
2371
+ const document = await fetchJson(`${base}/.well-known/openid-configuration`);
2372
+ return toDiscoveryDocument(document, issuer);
2373
+ };
2374
+ var fetchJwks = async (jwksUri) => {
2375
+ const body = await fetchJson(jwksUri);
2376
+ const value = Reflect.get(body ?? {}, "keys");
2377
+ if (!Array.isArray(value)) {
2378
+ throw new Error('JWKS response is missing a "keys" array');
2379
+ }
2380
+ const keys = value;
2381
+ return keys;
2382
+ };
2383
+ var createOIDCClient = async (config) => {
2384
+ const discovery = await fetchDiscoveryDocument(config.issuer);
2385
+ const scopes = config.scopes !== undefined && config.scopes.length > 0 ? config.scopes : DEFAULT_SCOPES;
2386
+ let cachedJwks;
2387
+ let jwksFetchedAtMs = 0;
2388
+ const resolveJwks = async (forceRefresh) => {
2389
+ const isStale = Date.now() - jwksFetchedAtMs > JWKS_REFETCH_COOLDOWN_MS;
2390
+ if (cachedJwks === undefined || forceRefresh && isStale) {
2391
+ cachedJwks = await fetchJwks(discovery.jwks_uri);
2392
+ jwksFetchedAtMs = Date.now();
2393
+ }
2394
+ return cachedJwks;
2395
+ };
2396
+ const createAuthorizationUrl = async (options) => {
2397
+ const url = new URL(discovery.authorization_endpoint);
2398
+ const challenge = await createS256CodeChallenge(options.codeVerifier);
2399
+ const { searchParams } = url;
2400
+ searchParams.set("client_id", config.clientId);
2401
+ searchParams.set("code_challenge", challenge);
2402
+ searchParams.set("code_challenge_method", "S256");
2403
+ searchParams.set("redirect_uri", config.redirectUri);
2404
+ searchParams.set("response_type", "code");
2405
+ searchParams.set("scope", (options.scope ?? scopes).join(" "));
2406
+ searchParams.set("state", options.state);
2407
+ if (options.nonce !== undefined) {
2408
+ searchParams.set("nonce", options.nonce);
2409
+ }
2410
+ return url;
2411
+ };
2412
+ const validateAuthorizationCode = async (options) => {
2413
+ const body = new URLSearchParams;
2414
+ body.set("client_id", config.clientId);
2415
+ body.set("client_secret", config.clientSecret);
2416
+ body.set("code", options.code);
2417
+ body.set("code_verifier", options.codeVerifier);
2418
+ body.set("grant_type", "authorization_code");
2419
+ body.set("redirect_uri", config.redirectUri);
2420
+ const response = await fetch(discovery.token_endpoint, {
2421
+ body,
2422
+ headers: {
2423
+ accept: "application/json",
2424
+ "content-type": "application/x-www-form-urlencoded"
2425
+ },
2426
+ method: "POST"
2427
+ });
2428
+ if (!response.ok) {
2429
+ throw new Error(`OIDC token request failed with status ${response.status}`);
2430
+ }
2431
+ const tokens = await response.json();
2432
+ return tokens;
2433
+ };
2434
+ const verifyToken = async (idToken, options) => {
2435
+ const jwks = await resolveJwks(false);
2436
+ const params = {
2437
+ audience: config.clientId,
2438
+ idToken,
2439
+ issuer: discovery.issuer,
2440
+ nonce: options?.nonce
2441
+ };
2442
+ try {
2443
+ return await verifyIdToken({ ...params, jwks });
2444
+ } catch (error) {
2445
+ const refreshed = await resolveJwks(true);
2446
+ if (refreshed === jwks)
2447
+ throw error;
2448
+ return verifyIdToken({ ...params, jwks: refreshed });
2449
+ }
2450
+ };
2451
+ const fetchUserProfile = async (accessToken) => {
2452
+ if (discovery.userinfo_endpoint === undefined) {
2453
+ throw new Error("OIDC provider does not expose a userinfo endpoint");
2454
+ }
2455
+ const response = await fetch(discovery.userinfo_endpoint, {
2456
+ headers: {
2457
+ accept: "application/json",
2458
+ authorization: `Bearer ${accessToken}`
2459
+ }
2460
+ });
2461
+ if (!response.ok) {
2462
+ throw new Error(`OIDC userinfo request failed with status ${response.status}`);
2463
+ }
2464
+ const profile = await response.json();
2465
+ return profile;
2466
+ };
2467
+ return {
2468
+ createAuthorizationUrl,
2469
+ discovery,
2470
+ fetchUserProfile,
2471
+ validateAuthorizationCode,
2472
+ verifyIdToken: verifyToken
2473
+ };
2474
+ };
2475
+ var oidcProviderOptions = Object.keys(providers).filter(isOIDCProviderOption);
2476
+ var pkceProviderOptions = Object.keys(providers).filter(isPKCEProviderOption);
2477
+ var providerOptions = Object.keys(providers).filter(isValidProviderOption);
2478
+ var refreshableProviderOptions = Object.keys(providers).filter(isRefreshableProviderOption);
2479
+ var revocableProviderOptions = Object.keys(providers).filter(isRevocableProviderOption);
2480
+ var scopeRequiredProviderOptions = Object.keys(providers).filter(isScopeRequiredProviderOption);
2481
+ var readPath = (value, path) => path.reduce((cursor, key) => cursor && typeof cursor === "object" ? Reflect.get(cursor, key) : undefined, value);
2482
+ var buildOAuth2Client = async (meta, config) => {
2483
+ const isConfigPropertyFunction = (cfgProp) => typeof cfgProp === "function";
2484
+ const resolveConfigProp = async (cfgProp) => {
2485
+ const result = isConfigPropertyFunction(cfgProp) ? cfgProp(config) : cfgProp;
2486
+ return result;
2487
+ };
2488
+ const authorizationUrl = await resolveConfigProp(meta.authorizationUrl);
2489
+ const tokenUrl = await resolveConfigProp(meta.tokenRequest.url);
2490
+ return {
2491
+ async createAuthorizationUrl(opts) {
2492
+ const { state, scope = [], searchParams = [], codeVerifier } = opts;
2493
+ const url = new URL(authorizationUrl);
2494
+ url.searchParams.set("response_type", "code");
2495
+ url.searchParams.set("client_id", config.clientId);
2496
+ if (config.redirectUri)
2497
+ url.searchParams.set("redirect_uri", config.redirectUri);
2498
+ if (state)
2499
+ url.searchParams.set("state", state);
2500
+ if (scope.length !== 0) {
2501
+ url.searchParams.set(meta.scopeParamName ?? "scope", scope.join(meta.scopeDelimiter ?? " "));
2502
+ }
2503
+ if (meta.PKCEMethod !== undefined) {
2504
+ if (!codeVerifier) {
2505
+ throw new Error("`codeVerifier` is required when PKCE is enabled");
2506
+ }
2507
+ const codeChallenge = meta.PKCEMethod === "S256" ? await createS256CodeChallenge(codeVerifier) : codeVerifier;
2508
+ url.searchParams.set("code_challenge_method", meta.PKCEMethod);
2509
+ url.searchParams.set("code_challenge", codeChallenge);
2510
+ }
2511
+ Object.entries(resolveConfigProp(meta.createAuthorizationURLSearchParams) ?? {}).forEach(([key, value]) => url.searchParams.set(key, value));
2512
+ searchParams.forEach(([key, value]) => url.searchParams.set(key, value));
2513
+ return url;
2514
+ },
2515
+ async fetchUserProfile(accessToken) {
2516
+ const { profileRequest } = meta;
2517
+ if (!profileRequest) {
2518
+ throw new Error("OIDC provider exposes identity through the id_token and does not define a UserInfo endpoint");
2519
+ }
2520
+ const {
2521
+ url,
2522
+ method,
2523
+ authIn,
2524
+ searchParams,
2525
+ body: profileBody,
2526
+ headers,
2527
+ encoding
2528
+ } = profileRequest;
2529
+ const endpoint = new URL(await resolveConfigProp(url));
2530
+ const resolvedBody = await resolveConfigProp(profileBody);
2531
+ new URLSearchParams(await resolveConfigProp(searchParams)).forEach((value, key) => endpoint.searchParams.append(key, value));
2532
+ let headerEntries = [];
2533
+ const rawHeaders = headers ? await resolveConfigProp(headers) : undefined;
2534
+ if (rawHeaders instanceof Headers)
2535
+ headerEntries = Array.from(rawHeaders.entries());
2536
+ else if (Array.isArray(rawHeaders))
2537
+ headerEntries = rawHeaders;
2538
+ else if (rawHeaders && typeof rawHeaders === "object")
2539
+ headerEntries = Object.entries(rawHeaders);
2540
+ const profileHeaders = Object.fromEntries(headerEntries.filter(([, value]) => value !== ""));
2541
+ if (authIn === "header") {
2542
+ profileHeaders.Authorization = `Bearer ${accessToken}`;
2543
+ } else if (authIn === "path") {
2544
+ endpoint.pathname = `${endpoint.pathname.replace(/\/+$/, "")}/${accessToken}`;
2545
+ } else {
2546
+ endpoint.searchParams.append("access_token", accessToken);
2547
+ }
2548
+ const init = { headers: profileHeaders, method };
2549
+ if (method === "POST" && resolvedBody !== undefined) {
2550
+ profileHeaders["Content-Type"] = encoding;
2551
+ init.body = encoding === "application/json" ? JSON.stringify(resolvedBody) : new URLSearchParams(resolvedBody).toString();
2552
+ }
2553
+ const profileTarget = endpoint.toString();
2554
+ const response = await fetch(profileTarget, init);
2555
+ if (!response.ok)
2556
+ throw await createOAuth2FetchError(response);
2557
+ return response.json();
2558
+ },
2559
+ async refreshAccessToken(refreshToken) {
2560
+ const { authIn, encoding } = meta.tokenRequest;
2561
+ const params = new URLSearchParams(meta.refreshAccessTokenBody);
2562
+ params.set("grant_type", "refresh_token");
2563
+ params.set("refresh_token", refreshToken);
2564
+ const { clientId } = config;
2565
+ let clientSecretValue;
2566
+ if (hasClientSecret(config)) {
2567
+ clientSecretValue = config.clientSecret;
2568
+ params.set("client_id", clientId);
2569
+ params.set("client_secret", clientSecretValue);
2570
+ }
2571
+ const request = createOAuth2Request({
2572
+ authIn,
2573
+ body: params,
2574
+ clientId,
2575
+ clientSecret: clientSecretValue,
2576
+ encoding,
2577
+ url: tokenUrl
2578
+ });
2579
+ const response = await fetch(request);
2580
+ if (!response.ok)
2581
+ throw await createOAuth2FetchError(response);
2582
+ return response.json();
2583
+ },
2584
+ async revokeToken(token) {
2585
+ const { revocationRequest } = meta;
2586
+ if (!revocationRequest) {
2587
+ throw new Error("Token revocation not defined for this provider");
2588
+ }
2589
+ const { url, authIn, body, headers, tokenParamName } = revocationRequest;
2590
+ const endpoint = await resolveConfigProp(url);
2591
+ const resolvedBody = await resolveConfigProp(body);
2592
+ const revocationBody = new URLSearchParams(resolvedBody);
2593
+ const revocationHeaders = new Headers(headers && await resolveConfigProp(headers));
2594
+ const { clientId } = config;
2595
+ const clientSecret = hasClientSecret(config) ? config.clientSecret : undefined;
2596
+ let request;
2597
+ if (authIn === "body") {
2598
+ revocationBody.set(tokenParamName, token);
2599
+ revocationBody.set("client_id", clientId);
2600
+ if (clientSecret)
2601
+ revocationBody.set("client_secret", clientSecret);
2602
+ request = createOAuth2Request({
2603
+ authIn: "body",
2604
+ body: revocationBody,
2605
+ clientId,
2606
+ clientSecret,
2607
+ encoding: "application/x-www-form-urlencoded",
2608
+ headers: revocationHeaders,
2609
+ url: endpoint.toString()
2610
+ });
2611
+ } else if (authIn === "header") {
2612
+ revocationHeaders.set("Authorization", `Bearer ${token}`);
2613
+ request = createOAuth2Request({
2614
+ authIn: "header",
2615
+ body: revocationBody,
2616
+ clientId,
2617
+ clientSecret,
2618
+ encoding: "application/x-www-form-urlencoded",
2619
+ headers: revocationHeaders,
2620
+ url: endpoint.toString()
2621
+ });
2622
+ } else {
2623
+ request = createOAuth2Request({
2624
+ authIn: "query",
2625
+ body: revocationBody,
2626
+ clientId,
2627
+ clientSecret,
2628
+ encoding: "application/x-www-form-urlencoded",
2629
+ headers: revocationHeaders,
2630
+ url: `${endpoint.toString()}?${tokenParamName}=${token}`
2631
+ });
2632
+ }
2633
+ const response = await fetch(request);
2634
+ if (!response.ok)
2635
+ throw await createOAuth2FetchError(response);
2636
+ },
2637
+ async validateAuthorizationCode(opts) {
2638
+ const { code, codeVerifier } = opts;
2639
+ const { authIn, encoding } = meta.tokenRequest;
2640
+ const bodyObj = {};
2641
+ for (const key in meta.validateAuthorizationCodeBody ?? {}) {
2642
+ const value = meta.validateAuthorizationCodeBody[key];
2643
+ if (typeof value === "string")
2644
+ bodyObj[key] = value;
2645
+ }
2646
+ bodyObj.grant_type = "authorization_code";
2647
+ bodyObj.code = code;
2648
+ if (config.redirectUri)
2649
+ bodyObj.redirect_uri = config.redirectUri;
2650
+ if (meta.PKCEMethod !== undefined) {
2651
+ if (!codeVerifier) {
2652
+ throw new Error("codeVerifier required when PKCE is enabled");
2653
+ }
2654
+ bodyObj.code_verifier = codeVerifier;
2655
+ }
2656
+ const payload = encoding === "application/json" ? bodyObj : new URLSearchParams(bodyObj);
2657
+ const request = createOAuth2Request({
2658
+ authIn,
2659
+ body: payload,
2660
+ clientId: config.clientId,
2661
+ clientSecret: hasClientSecret(config) ? config.clientSecret : undefined,
2662
+ encoding,
2663
+ url: tokenUrl
2664
+ });
2665
+ const response = await fetch(request);
2666
+ if (!response.ok)
2667
+ throw await createOAuth2FetchError(response);
2668
+ const tokenResponse = await response.json();
2669
+ if (!tokenResponse || typeof tokenResponse !== "object") {
2670
+ throw new Error("OAuth token endpoint returned a non-object response");
2671
+ }
2672
+ const oauthError = Reflect.get(tokenResponse, "error");
2673
+ if (typeof oauthError === "string" && oauthError.length > 0) {
2674
+ throw new Error(`OAuth token exchange failed: ${oauthError}`);
2675
+ }
2676
+ const nestedToken = meta.accessTokenPath ? readPath(tokenResponse, meta.accessTokenPath) : undefined;
2677
+ if (typeof nestedToken === "string" && nestedToken.length > 0 && tokenResponse && typeof tokenResponse === "object") {
2678
+ tokenResponse.access_token = nestedToken;
2679
+ }
2680
+ const accessToken = Reflect.get(tokenResponse, "access_token");
2681
+ if (typeof accessToken !== "string" || accessToken.length === 0) {
2682
+ throw new Error("OAuth token endpoint returned no access_token");
2683
+ }
2684
+ return tokenResponse;
2685
+ }
2686
+ };
2687
+ };
2688
+ var createCustomOAuth2Client = (providerConfig, credentials) => buildOAuth2Client(providerConfig, credentials);
2689
+ var createOAuth2Client = (providerName, config) => buildOAuth2Client(providers[providerName], config);
2690
+
2691
+ // src/providers/clients.ts
2692
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2693
+ var isProviderClientConfig = (value) => isRecord(value) && ("credentials" in value);
2694
+ var isCustomClientConfig = (value) => isRecord(value) && ("credentials" in value) && ("providerConfig" in value);
2695
+ var normalizeCustomClients = (providerName, providerConfig) => {
2696
+ if (isCustomClientConfig(providerConfig))
2697
+ return { "": providerConfig };
2698
+ if (!isRecord(providerConfig) || Object.keys(providerConfig).length === 0) {
2699
+ throw new Error(`Invalid custom provider configuration for ${providerName}`);
2700
+ }
2701
+ Object.entries(providerConfig).forEach(([clientName, clientConfig]) => {
2702
+ if (!isCustomClientConfig(clientConfig)) {
2703
+ throw new Error(`Invalid custom client configuration for ${providerName}.${clientName}`);
2704
+ }
2705
+ });
2706
+ return providerConfig;
2707
+ };
2708
+ var buildCustomProviderGroups = async (customProviders) => {
2709
+ const groups = await Promise.all(Object.entries(customProviders).map(async ([providerName, config]) => {
2710
+ if (isValidProviderOption(providerName)) {
2711
+ throw new Error(`Custom provider "${providerName}" collides with a built-in provider \u2014 configure it under providersConfiguration instead`);
2712
+ }
2713
+ const clients = normalizeCustomClients(providerName, config);
2714
+ const entries = await Promise.all(Object.entries(clients).map(async ([clientName, clientConfig]) => {
2715
+ const providerInstance = await createCustomOAuth2Client(clientConfig.providerConfig, clientConfig.credentials);
2716
+ return [
2717
+ clientName,
2718
+ {
2719
+ clientName: clientName.length > 0 ? clientName : undefined,
2720
+ providerConfiguration: clientConfig.providerConfig,
2721
+ providerInstance,
2722
+ requiresPKCE: clientConfig.providerConfig.PKCEMethod !== undefined,
2723
+ scope: clientConfig.scope,
2724
+ searchParams: clientConfig.searchParams
2725
+ }
2726
+ ];
2727
+ }));
2728
+ return [
2729
+ providerName,
2730
+ {
2731
+ entries: Object.fromEntries(entries),
2732
+ isSingleClient: entries.length === 1 && entries[0]?.[0] === ""
2733
+ }
2734
+ ];
2735
+ }));
2736
+ return Object.fromEntries(groups);
2737
+ };
2738
+ var buildClientProviders = async (providersConfiguration, createOAuth2ClientFn, customProviders) => {
2739
+ const customGroups = customProviders ? await buildCustomProviderGroups(customProviders) : {};
2740
+ const normalized = normalizeProvidersConfiguration(providersConfiguration);
2741
+ const groups = await Promise.all(Object.entries(normalized).map(async ([providerName, clients]) => {
2742
+ if (!isValidProviderOption(providerName)) {
2743
+ throw new Error(`Invalid provider configuration for ${providerName}`);
2744
+ }
2745
+ const entries = await Promise.all(Object.entries(clients).map(async ([clientName, providerConfig]) => {
2746
+ const providerInstance = await createOAuth2ClientFn(providerName, providerConfig.credentials);
2747
+ return [
2748
+ clientName,
2749
+ {
2750
+ clientName: clientName.length > 0 ? clientName : undefined,
2751
+ providerConfiguration: providers[providerName],
2752
+ providerInstance,
2753
+ requiresPKCE: providers[providerName].PKCEMethod !== undefined,
2754
+ scope: providerConfig.scope,
2755
+ searchParams: providerConfig.searchParams
2756
+ }
2757
+ ];
2758
+ }));
2759
+ return [
2760
+ providerName,
2761
+ {
2762
+ entries: Object.fromEntries(entries),
2763
+ isSingleClient: entries.length === 1 && entries[0]?.[0] === ""
2764
+ }
2765
+ ];
2766
+ }));
2767
+ return { ...customGroups, ...Object.fromEntries(groups) };
2768
+ };
2769
+ var normalizeClientConfig = (providerName, clientName, clientConfig) => {
2770
+ if (!isProviderClientConfig(clientConfig)) {
2771
+ throw new Error(`Invalid client configuration for ${providerName}.${clientName}`);
2772
+ }
2773
+ return [clientName, clientConfig];
2774
+ };
2775
+ var normalizeProviderClients = (providerName, providerConfig) => {
2776
+ if (isProviderClientConfig(providerConfig)) {
2777
+ return { "": providerConfig };
2778
+ }
2779
+ if (!isRecord(providerConfig) || Object.keys(providerConfig).length === 0) {
2780
+ throw new Error(`Invalid provider configuration for ${providerName}`);
2781
+ }
2782
+ return Object.fromEntries(Object.entries(providerConfig).map(([clientName, clientConfig]) => normalizeClientConfig(providerName, clientName, clientConfig)));
2783
+ };
2784
+ var normalizeProvidersConfiguration = (providersConfiguration) => {
2785
+ const entries = Object.entries(providersConfiguration).flatMap(([providerName, providerConfig]) => {
2786
+ if (!isValidProviderOption(providerName) || !providerConfig) {
2787
+ return [];
2788
+ }
2789
+ return [
2790
+ [
2791
+ providerName,
2792
+ normalizeProviderClients(providerName, providerConfig)
2793
+ ]
2794
+ ];
2795
+ });
2796
+ return Object.fromEntries(entries);
2797
+ };
2798
+ var resolveClientProviderEntry = ({
2799
+ clientName,
2800
+ clientProviders,
2801
+ providerName
2802
+ }) => {
2803
+ if (!providerName) {
2804
+ return { error: "Provider is required" };
2805
+ }
2806
+ const group = clientProviders[providerName];
2807
+ if (!group) {
2808
+ return { error: "Client provider not found" };
2809
+ }
2810
+ if (group.isSingleClient) {
2811
+ const entry2 = group.entries[""];
2812
+ if (!entry2) {
2813
+ return { error: "Client provider not found" };
2814
+ }
2815
+ return { entry: entry2 };
2816
+ }
2817
+ const requestedClient = clientName?.trim();
2818
+ if (!requestedClient) {
2819
+ return { error: "Client variant is required" };
2820
+ }
2821
+ const entry = group.entries[requestedClient];
2822
+ if (!entry) {
2823
+ return { error: "Client variant not found" };
2824
+ }
2825
+ return { entry };
2826
+ };
2827
+ var resolveProviderClientConfiguration = ({
2828
+ clientName,
2829
+ providerName,
2830
+ providersConfiguration
2831
+ }) => {
2832
+ const normalized = normalizeProvidersConfiguration(providersConfiguration);
2833
+ const clients = normalized[providerName];
2834
+ if (!clients) {
2835
+ return { error: "Client provider not found" };
2836
+ }
2837
+ const keys = Object.keys(clients);
2838
+ if (keys.length === 1 && keys[0] === "") {
2839
+ return { config: clients[""] };
2840
+ }
2841
+ const requestedClient = clientName?.trim();
2842
+ if (!requestedClient) {
2843
+ return { error: "Client variant is required" };
2844
+ }
2845
+ const config = clients[requestedClient];
2846
+ if (!config) {
2847
+ return { error: "Client variant not found" };
2848
+ }
2849
+ return { config };
2850
+ };
2851
+
2852
+ // src/linkedProviders/resolver.ts
2853
+ var uniqueStrings = (values) => [...new Set(values)];
2854
+ var getEffectiveScopes = (grant, binding) => {
2855
+ if (binding.availableScopes.length === 0) {
2856
+ return uniqueStrings(grant.grantedScopes);
2857
+ }
2858
+ const bindingScopeSet = new Set(binding.availableScopes);
2859
+ return uniqueStrings(grant.grantedScopes.filter((scope) => bindingScopeSet.has(scope)));
2860
+ };
2861
+ var hasRequiredScopes = (availableScopes, requiredScopes) => (requiredScopes ?? []).every((scope) => availableScopes.includes(scope));
2862
+ var isGrantUsable = (grant) => grant.status === "active" || grant.status === "refresh_required";
2863
+ var isBindingUsable = (binding) => binding.status === "active";
2864
+ var needsRefresh = (lease, now, minValidityMs) => {
2865
+ if (!lease)
2866
+ return true;
2867
+ if (lease.expiresAt === undefined)
2868
+ return false;
2869
+ return lease.expiresAt <= now + (minValidityMs ?? 0);
2870
+ };
2871
+ var ensureLeaseScopes = (lease, requiredScopes) => {
2872
+ if (!hasRequiredScopes(lease.grantedScopes, requiredScopes)) {
2873
+ throw new Error("Linked provider access token lease is missing required scopes");
2874
+ }
2875
+ };
2876
+ var ensureLeaseValidity = (lease, now, minValidityMs) => {
2877
+ if (lease.expiresAt === undefined)
2878
+ return;
2879
+ if (lease.expiresAt <= now + (minValidityMs ?? 0)) {
2880
+ throw new Error("Linked provider access token lease does not satisfy minimum validity");
2881
+ }
2882
+ };
2883
+ var buildResolvedCredential = (grant, binding) => ({
2884
+ authProviderKey: grant.authProviderKey,
2885
+ bindingId: binding.id,
2886
+ capabilities: binding.capabilities ? [...binding.capabilities] : undefined,
2887
+ connectorProvider: binding.connectorProvider,
2888
+ email: binding.email,
2889
+ externalAccountId: binding.externalAccountId,
2890
+ externalAccountType: binding.externalAccountType,
2891
+ grantId: grant.id,
2892
+ label: binding.label,
2893
+ metadata: {
2894
+ ...grant.metadata ?? {},
2895
+ ...binding.metadata ?? {}
2896
+ },
2897
+ ownerRef: grant.ownerRef,
2898
+ providerFamily: grant.providerFamily,
2899
+ scopes: getEffectiveScopes(grant, binding),
2900
+ username: binding.username
2901
+ });
2902
+ var annotateFailureMetadata = (metadata, report, now) => ({
2903
+ ...metadata ?? {},
2904
+ lastCredentialFailureAt: now,
2905
+ lastCredentialFailureCode: report.code,
2906
+ lastCredentialFailureMessage: report.message,
2907
+ lastCredentialFailureRetryAt: report.retryAt
2908
+ });
2909
+ var sortNewestFirst = (items) => [...items].sort((left, right) => right.updatedAt - left.updatedAt);
2910
+ var resolveGrantFailureStatus = (grant, report) => {
2911
+ if (report.code === "unauthorized" || report.code === "revoked") {
2912
+ return "revoked";
2913
+ }
2914
+ return grant.status;
2915
+ };
2916
+ var resolveBindingFailureStatus = (binding, report) => {
2917
+ if (report.code === "unauthorized" || report.code === "revoked") {
2918
+ return "disconnected";
2919
+ }
2920
+ if (report.code === "insufficient_scope") {
2921
+ return "restricted";
2922
+ }
2923
+ return binding.status;
2924
+ };
2925
+ var buildNextGrant = (grant, report, currentTime) => ({
2926
+ ...grant,
2927
+ lastRefreshError: report.message ?? report.code,
2928
+ metadata: annotateFailureMetadata(grant.metadata, report, currentTime),
2929
+ status: resolveGrantFailureStatus(grant, report),
2930
+ updatedAt: currentTime
2931
+ });
2932
+ var buildNextBinding = (binding, report, currentTime) => ({
2933
+ ...binding,
2934
+ metadata: annotateFailureMetadata(binding.metadata, report, currentTime),
2935
+ status: resolveBindingFailureStatus(binding, report),
2936
+ updatedAt: currentTime
2937
+ });
2938
+ var resolveBindingCredential = async (grantStore, binding, input) => {
2939
+ const grant = await grantStore.getGrant(binding.grantId);
2940
+ if (!grant || grant.ownerRef !== input.ownerRef || !isGrantUsable(grant)) {
2941
+ return null;
2942
+ }
2943
+ const effectiveScopes = getEffectiveScopes(grant, binding);
2944
+ if (!hasRequiredScopes(effectiveScopes, input.requiredScopes)) {
2945
+ return null;
2946
+ }
2947
+ return buildResolvedCredential(grant, binding);
2948
+ };
2949
+ var createLinkedProviderCredentialResolver = ({
2950
+ grantStore,
2951
+ bindingStore,
2952
+ loadAccessTokenLease,
2953
+ refreshAccessTokenLease,
2954
+ now = () => Date.now(),
2955
+ onReportFailure
2956
+ }) => ({
2957
+ getAccessToken: async (credential, input) => {
2958
+ const binding = await bindingStore.getBinding(credential.bindingId);
2959
+ if (!binding || !isBindingUsable(binding)) {
2960
+ throw new Error("Linked provider binding is unavailable");
2961
+ }
2962
+ const grant = await grantStore.getGrant(credential.grantId);
2963
+ if (!grant || !isGrantUsable(grant)) {
2964
+ throw new Error("Linked provider grant is unavailable");
2965
+ }
2966
+ const requiredScopes = input?.requiredScopes;
2967
+ const effectiveScopes = getEffectiveScopes(grant, binding);
2968
+ if (!hasRequiredScopes(effectiveScopes, requiredScopes)) {
2969
+ throw new Error("Linked provider credential is missing required scopes");
2970
+ }
2971
+ const currentTime = now();
2972
+ let lease = await loadAccessTokenLease(grant);
2973
+ if (needsRefresh(lease, currentTime, input?.minValidityMs)) {
2974
+ if (!refreshAccessTokenLease) {
2975
+ throw new Error("Linked provider access token lease requires refresh");
2976
+ }
2977
+ const refreshed = await refreshAccessTokenLease(grant, input);
2978
+ if (!refreshed) {
2979
+ throw new Error("Linked provider access token refresh failed");
2980
+ }
2981
+ await grantStore.saveGrant(refreshed.grant);
2982
+ ({ lease } = refreshed);
2983
+ }
2984
+ if (!lease) {
2985
+ throw new Error("Linked provider access token lease is unavailable");
2986
+ }
2987
+ ensureLeaseScopes(lease, requiredScopes);
2988
+ ensureLeaseValidity(lease, currentTime, input?.minValidityMs);
2989
+ return lease;
2990
+ },
2991
+ listBindings: async ({ ownerRef, connectorProvider, status }) => sortNewestFirst(await bindingStore.listBindingsByOwner(ownerRef)).filter((binding) => (connectorProvider === undefined || binding.connectorProvider === connectorProvider) && (status === undefined || binding.status === status)),
2992
+ reportFailure: async (credential, report) => {
2993
+ const currentTime = now();
2994
+ const grant = await grantStore.getGrant(credential.grantId);
2995
+ const binding = await bindingStore.getBinding(credential.bindingId);
2996
+ if (grant) {
2997
+ await grantStore.saveGrant(buildNextGrant(grant, report, currentTime));
2998
+ }
2999
+ if (binding) {
3000
+ await bindingStore.saveBinding(buildNextBinding(binding, report, currentTime));
3001
+ }
3002
+ await onReportFailure?.({
3003
+ binding: binding ?? undefined,
3004
+ credential,
3005
+ grant: grant ?? undefined,
3006
+ report
3007
+ });
3008
+ },
3009
+ resolveCredential: async (input) => {
3010
+ const bindings = sortNewestFirst(await bindingStore.listBindingsByOwner(input.ownerRef)).filter((binding) => binding.connectorProvider === input.connectorProvider && isBindingUsable(binding) && (input.bindingId === undefined || binding.id === input.bindingId) && (input.externalAccountId === undefined || binding.externalAccountId === input.externalAccountId));
3011
+ return bindings.reduce(async (pendingCredential, binding) => {
3012
+ const credential = await pendingCredential;
3013
+ if (credential)
3014
+ return credential;
3015
+ return resolveBindingCredential(grantStore, binding, input);
3016
+ }, Promise.resolve(null));
3017
+ }
3018
+ });
3019
+
3020
+ // src/linkedProviders/oauthResolver.ts
3021
+ var getGrantedScopes = (scopeValue, fallbackScopes) => {
3022
+ if (typeof scopeValue === "string" && scopeValue.trim().length > 0) {
3023
+ return [...new Set(scopeValue.split(/\s+/).filter(Boolean))];
3024
+ }
3025
+ return [...new Set(fallbackScopes.filter(Boolean))];
3026
+ };
3027
+ var parseExpiresInSeconds = (expiresIn) => {
3028
+ if (typeof expiresIn === "number") {
3029
+ return expiresIn;
3030
+ }
3031
+ if (typeof expiresIn === "string" && expiresIn.trim().length > 0) {
3032
+ return Number(expiresIn);
3033
+ }
3034
+ return Number.NaN;
3035
+ };
3036
+ var getExpiresAt = (tokenResponse) => {
3037
+ const expiresInSeconds = parseExpiresInSeconds(tokenResponse.expires_in);
3038
+ if (!Number.isFinite(expiresInSeconds) || expiresInSeconds <= 0) {
3039
+ return;
3040
+ }
3041
+ return Date.now() + expiresInSeconds * 1000;
3042
+ };
3043
+ var buildClientEntry = (providerName, providersConfiguration) => {
3044
+ if (!isValidProviderOption(providerName)) {
3045
+ return null;
3046
+ }
3047
+ const resolvedProviderClientConfiguration = resolveProviderClientConfiguration({
3048
+ providerName,
3049
+ providersConfiguration
3050
+ });
3051
+ if ("error" in resolvedProviderClientConfiguration || !resolvedProviderClientConfiguration.config) {
3052
+ return null;
3053
+ }
3054
+ return createOAuth2Client(providerName, resolvedProviderClientConfiguration.config.credentials).then((providerInstance) => [providerName, providerInstance]);
3055
+ };
3056
+ var createOAuthLinkedProviderCredentialResolver = async ({
3057
+ bindingStore,
3058
+ grantStore,
3059
+ now,
3060
+ providersConfiguration
3061
+ }) => {
3062
+ const clientEntries = Object.keys(providersConfiguration).map((providerName) => buildClientEntry(providerName, providersConfiguration)).filter((entry) => entry !== null);
3063
+ await Promise.all(clientEntries);
3064
+ return createLinkedProviderCredentialResolver({
3065
+ bindingStore,
3066
+ grantStore,
3067
+ now,
3068
+ loadAccessTokenLease: async (grant) => grant.accessTokenCiphertext ? {
3069
+ accessToken: grant.accessTokenCiphertext,
3070
+ expiresAt: grant.expiresAt,
3071
+ grantedScopes: grant.grantedScopes,
3072
+ tokenType: grant.tokenType
3073
+ } : null,
3074
+ refreshAccessTokenLease: async (grant) => {
3075
+ if (!isValidProviderOption(grant.authProviderKey) || !grant.refreshTokenCiphertext) {
3076
+ return null;
3077
+ }
3078
+ const providerKey = grant.authProviderKey;
3079
+ const providerClientName = typeof grant.metadata?.providerClient === "string" && grant.metadata.providerClient.trim().length > 0 ? grant.metadata.providerClient.trim() : undefined;
3080
+ const resolvedProviderClientConfiguration = resolveProviderClientConfiguration({
3081
+ clientName: providerClientName,
3082
+ providerName: providerKey,
3083
+ providersConfiguration
3084
+ });
3085
+ if ("error" in resolvedProviderClientConfiguration || !resolvedProviderClientConfiguration.config) {
3086
+ return null;
3087
+ }
3088
+ const providerClient = await createOAuth2Client(providerKey, resolvedProviderClientConfiguration.config.credentials);
3089
+ if (!providerClient || !isRefreshableOAuth2Client(providerKey, providerClient)) {
3090
+ return null;
3091
+ }
3092
+ const tokenResponse = await providerClient.refreshAccessToken(grant.refreshTokenCiphertext);
3093
+ const refreshedAt = Date.now();
3094
+ const grantedScopes = getGrantedScopes(Reflect.get(tokenResponse, "scope"), grant.grantedScopes);
3095
+ const tokenType = Reflect.get(tokenResponse, "token_type");
3096
+ const refreshedGrant = {
3097
+ ...grant,
3098
+ accessTokenCiphertext: tokenResponse.access_token,
3099
+ expiresAt: getExpiresAt(tokenResponse),
3100
+ grantedScopes,
3101
+ lastRefreshedAt: refreshedAt,
3102
+ lastRefreshError: undefined,
3103
+ refreshTokenCiphertext: tokenResponse.refresh_token ?? grant.refreshTokenCiphertext,
3104
+ status: "active",
3105
+ tokenType: typeof tokenType === "string" ? tokenType : grant.tokenType,
3106
+ updatedAt: refreshedAt
3107
+ };
3108
+ return {
3109
+ grant: refreshedGrant,
3110
+ lease: {
3111
+ accessToken: refreshedGrant.accessTokenCiphertext ?? "",
3112
+ expiresAt: refreshedGrant.expiresAt,
3113
+ grantedScopes: refreshedGrant.grantedScopes,
3114
+ tokenType: refreshedGrant.tokenType
3115
+ }
3116
+ };
3117
+ }
3118
+ });
3119
+ };
3120
+
3121
+ // src/linkedProviders/oauthAccountResolver.ts
3122
+ var bindingId = (accountId) => `oauth-account:${accountId}`;
3123
+ var accountIdFromBinding = (id) => {
3124
+ const prefix = "oauth-account:";
3125
+ return id.startsWith(prefix) ? id.slice(prefix.length) : null;
3126
+ };
3127
+ var toGrant = (account) => ({
3128
+ accessTokenCiphertext: account.accessToken,
3129
+ authProviderKey: account.authProviderKey,
3130
+ createdAt: account.createdAt,
3131
+ expiresAt: account.expiresAt,
3132
+ grantedScopes: [...account.grantedScopes],
3133
+ id: account.id,
3134
+ metadata: account.metadata,
3135
+ ownerRef: account.ownerRef,
3136
+ providerFamily: account.authProviderKey,
3137
+ providerSubject: account.providerSubject,
3138
+ refreshTokenCiphertext: account.refreshToken,
3139
+ status: account.status,
3140
+ tokenType: account.tokenType,
3141
+ updatedAt: account.updatedAt
3142
+ });
3143
+ var toBinding = (account) => ({
3144
+ availableScopes: [...account.grantedScopes],
3145
+ connectorProvider: account.authProviderKey,
3146
+ createdAt: account.createdAt,
3147
+ externalAccountId: account.providerSubject,
3148
+ externalAccountType: "user",
3149
+ grantId: account.id,
3150
+ id: bindingId(account.id),
3151
+ metadata: account.metadata,
3152
+ status: account.status === "revoked" || account.status === "error" ? "disconnected" : "active",
3153
+ updatedAt: account.updatedAt
3154
+ });
3155
+ var accountWithGrant = (account, grant) => ({
3156
+ ...account,
3157
+ accessToken: grant.accessTokenCiphertext,
3158
+ authProviderKey: grant.authProviderKey,
3159
+ expiresAt: grant.expiresAt,
3160
+ grantedScopes: [...grant.grantedScopes],
3161
+ metadata: grant.metadata,
3162
+ ownerRef: grant.ownerRef,
3163
+ providerSubject: grant.providerSubject,
3164
+ refreshToken: grant.refreshTokenCiphertext,
3165
+ status: grant.status,
3166
+ tokenType: grant.tokenType,
3167
+ updatedAt: grant.updatedAt
3168
+ });
3169
+ var accountStatusForBinding = (account, binding) => {
3170
+ if (binding.status === "disconnected")
3171
+ return "revoked";
3172
+ if (binding.status === "restricted")
3173
+ return "error";
3174
+ return account.status;
3175
+ };
3176
+ var createOAuthAccountLinkedProviderCredentialResolver = async ({
3177
+ accountStore,
3178
+ now,
3179
+ providersConfiguration
3180
+ }) => {
3181
+ const grantStore = {
3182
+ getGrant: async (id) => {
3183
+ const account = await accountStore.getAccount(id);
3184
+ return account ? toGrant(account) : undefined;
3185
+ },
3186
+ listGrantsByOwner: async (ownerRef) => (await accountStore.listAccountsByOwner(ownerRef)).map(toGrant),
3187
+ saveGrant: async (grant) => {
3188
+ const account = await accountStore.getAccount(grant.id);
3189
+ if (!account)
3190
+ throw new Error("OAuth linked account is unavailable");
3191
+ await accountStore.saveAccount(accountWithGrant(account, grant));
3192
+ }
3193
+ };
3194
+ const bindingStore = {
3195
+ getBinding: async (id) => {
3196
+ const accountId = accountIdFromBinding(id);
3197
+ if (!accountId)
3198
+ return;
3199
+ const account = await accountStore.getAccount(accountId);
3200
+ return account ? toBinding(account) : undefined;
3201
+ },
3202
+ listBindingsByGrant: async (grantId) => {
3203
+ const account = await accountStore.getAccount(grantId);
3204
+ return account ? [toBinding(account)] : [];
3205
+ },
3206
+ listBindingsByOwner: async (ownerRef) => (await accountStore.listAccountsByOwner(ownerRef)).map(toBinding),
3207
+ saveBinding: async (binding) => {
3208
+ const account = await accountStore.getAccount(binding.grantId);
3209
+ if (!account)
3210
+ throw new Error("OAuth linked account is unavailable");
3211
+ await accountStore.saveAccount({
3212
+ ...account,
3213
+ metadata: binding.metadata,
3214
+ status: accountStatusForBinding(account, binding),
3215
+ updatedAt: binding.updatedAt
3216
+ });
3217
+ }
3218
+ };
3219
+ return createOAuthLinkedProviderCredentialResolver({
3220
+ bindingStore,
3221
+ grantStore,
3222
+ ...now ? { now } : {},
3223
+ providersConfiguration
3224
+ });
3225
+ };
3226
+ export {
3227
+ createOAuthLinkedProviderCredentialResolver,
3228
+ createOAuthAccountLinkedProviderCredentialResolver,
3229
+ createLinkedProviderCredentialResolver
3230
+ };
3231
+
3232
+ //# debugId=B59DE2430BCDE3E764756E2164756E21
3233
+ //# sourceMappingURL=index.js.map