@better-auth/core 1.5.0-beta.2 → 1.5.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +15 -12
- package/README.md +17 -0
- package/dist/api/index.d.mts +280 -2
- package/dist/api/index.mjs +4 -2
- package/dist/api/index.mjs.map +1 -0
- package/dist/async_hooks/index.d.mts +2 -1
- package/dist/async_hooks/index.mjs +2 -1
- package/dist/async_hooks/index.mjs.map +1 -0
- package/dist/async_hooks/pure.index.d.mts +2 -1
- package/dist/async_hooks/pure.index.mjs +2 -1
- package/dist/async_hooks/pure.index.mjs.map +1 -0
- package/dist/context/endpoint-context.d.mts +20 -0
- package/dist/context/endpoint-context.mjs +32 -0
- package/dist/context/endpoint-context.mjs.map +1 -0
- package/dist/context/global.d.mts +7 -0
- package/dist/context/global.mjs +38 -0
- package/dist/context/global.mjs.map +1 -0
- package/dist/context/index.d.mts +5 -53
- package/dist/context/index.mjs +5 -2
- package/dist/context/request-state.d.mts +28 -0
- package/dist/context/request-state.mjs +50 -0
- package/dist/context/request-state.mjs.map +1 -0
- package/dist/context/transaction.d.mts +25 -0
- package/dist/context/transaction.mjs +96 -0
- package/dist/context/transaction.mjs.map +1 -0
- package/dist/db/adapter/factory.d.mts +20 -0
- package/dist/db/adapter/factory.mjs +725 -0
- package/dist/db/adapter/factory.mjs.map +1 -0
- package/dist/db/adapter/get-default-field-name.d.mts +19 -0
- package/dist/db/adapter/get-default-field-name.mjs +39 -0
- package/dist/db/adapter/get-default-field-name.mjs.map +1 -0
- package/dist/db/adapter/get-default-model-name.d.mts +13 -0
- package/dist/db/adapter/get-default-model-name.mjs +33 -0
- package/dist/db/adapter/get-default-model-name.mjs.map +1 -0
- package/dist/db/adapter/get-field-attributes.d.mts +30 -0
- package/dist/db/adapter/get-field-attributes.mjs +40 -0
- package/dist/db/adapter/get-field-attributes.mjs.map +1 -0
- package/dist/db/adapter/get-field-name.d.mts +19 -0
- package/dist/db/adapter/get-field-name.mjs +34 -0
- package/dist/db/adapter/get-field-name.mjs.map +1 -0
- package/dist/db/adapter/get-id-field.d.mts +40 -0
- package/dist/db/adapter/get-id-field.mjs +68 -0
- package/dist/db/adapter/get-id-field.mjs.map +1 -0
- package/dist/db/adapter/get-model-name.d.mts +13 -0
- package/dist/db/adapter/get-model-name.mjs +24 -0
- package/dist/db/adapter/get-model-name.mjs.map +1 -0
- package/dist/db/adapter/index.d.mts +520 -2
- package/dist/db/adapter/index.mjs +27 -972
- package/dist/db/adapter/index.mjs.map +1 -0
- package/dist/db/adapter/types.d.mts +108 -0
- package/dist/db/adapter/utils.d.mts +8 -0
- package/dist/db/adapter/utils.mjs +39 -0
- package/dist/db/adapter/utils.mjs.map +1 -0
- package/dist/db/get-tables.d.mts +9 -0
- package/dist/{get-tables-CMc_Emww.mjs → db/get-tables.mjs} +52 -39
- package/dist/db/get-tables.mjs.map +1 -0
- package/dist/db/index.d.mts +10 -2
- package/dist/db/index.mjs +7 -60
- package/dist/db/plugin.d.mts +13 -0
- package/dist/db/schema/account.d.mts +30 -0
- package/dist/db/schema/account.mjs +20 -0
- package/dist/db/schema/account.mjs.map +1 -0
- package/dist/db/schema/rate-limit.d.mts +20 -0
- package/dist/db/schema/rate-limit.mjs +12 -0
- package/dist/db/schema/rate-limit.mjs.map +1 -0
- package/dist/db/schema/session.d.mts +25 -0
- package/dist/db/schema/session.mjs +15 -0
- package/dist/db/schema/session.mjs.map +1 -0
- package/dist/db/schema/shared.d.mts +11 -0
- package/dist/db/schema/shared.mjs +12 -0
- package/dist/db/schema/shared.mjs.map +1 -0
- package/dist/db/schema/user.d.mts +24 -0
- package/dist/db/schema/user.mjs +14 -0
- package/dist/db/schema/user.mjs.map +1 -0
- package/dist/db/schema/verification.d.mts +23 -0
- package/dist/db/schema/verification.mjs +13 -0
- package/dist/db/schema/verification.mjs.map +1 -0
- package/dist/db/type.d.mts +169 -0
- package/dist/env/color-depth.d.mts +5 -0
- package/dist/env/color-depth.mjs +89 -0
- package/dist/env/color-depth.mjs.map +1 -0
- package/dist/env/env-impl.d.mts +33 -0
- package/dist/env/env-impl.mjs +83 -0
- package/dist/env/env-impl.mjs.map +1 -0
- package/dist/env/index.d.mts +4 -2
- package/dist/env/index.mjs +3 -1
- package/dist/{index-BRBu0-5h.d.mts → env/logger.d.mts} +2 -35
- package/dist/env/logger.mjs +82 -0
- package/dist/env/logger.mjs.map +1 -0
- package/dist/error/codes.d.mts +69 -0
- package/dist/{error-C7mY-p0f.mjs → error/codes.mjs} +7 -30
- package/dist/error/codes.mjs.map +1 -0
- package/dist/error/index.d.mts +6 -187
- package/dist/error/index.mjs +29 -4
- package/dist/error/index.mjs.map +1 -0
- package/dist/index.d.mts +8 -2
- package/dist/oauth2/client-credentials-token.d.mts +58 -0
- package/dist/oauth2/client-credentials-token.mjs +67 -0
- package/dist/oauth2/client-credentials-token.mjs.map +1 -0
- package/dist/oauth2/create-authorization-url.d.mts +48 -0
- package/dist/oauth2/create-authorization-url.mjs +44 -0
- package/dist/oauth2/create-authorization-url.mjs.map +1 -0
- package/dist/oauth2/index.d.mts +8 -2
- package/dist/oauth2/index.mjs +7 -3
- package/dist/oauth2/oauth-provider.d.mts +195 -0
- package/dist/oauth2/refresh-access-token.d.mts +56 -0
- package/dist/oauth2/refresh-access-token.mjs +76 -0
- package/dist/oauth2/refresh-access-token.mjs.map +1 -0
- package/dist/oauth2/utils.d.mts +8 -0
- package/dist/oauth2/utils.mjs +28 -0
- package/dist/oauth2/utils.mjs.map +1 -0
- package/dist/oauth2/validate-authorization-code.d.mts +88 -0
- package/dist/oauth2/validate-authorization-code.mjs +83 -0
- package/dist/oauth2/validate-authorization-code.mjs.map +1 -0
- package/dist/oauth2/verify.d.mts +43 -0
- package/dist/oauth2/verify.mjs +96 -0
- package/dist/oauth2/verify.mjs.map +1 -0
- package/dist/social-providers/apple.d.mts +120 -0
- package/dist/social-providers/apple.mjs +105 -0
- package/dist/social-providers/apple.mjs.map +1 -0
- package/dist/social-providers/atlassian.d.mts +73 -0
- package/dist/social-providers/atlassian.mjs +84 -0
- package/dist/social-providers/atlassian.mjs.map +1 -0
- package/dist/social-providers/cognito.d.mts +88 -0
- package/dist/social-providers/cognito.mjs +166 -0
- package/dist/social-providers/cognito.mjs.map +1 -0
- package/dist/social-providers/discord.d.mts +127 -0
- package/dist/social-providers/discord.mjs +65 -0
- package/dist/social-providers/discord.mjs.map +1 -0
- package/dist/social-providers/dropbox.d.mts +72 -0
- package/dist/social-providers/dropbox.mjs +76 -0
- package/dist/social-providers/dropbox.mjs.map +1 -0
- package/dist/social-providers/facebook.d.mts +82 -0
- package/dist/social-providers/facebook.mjs +121 -0
- package/dist/social-providers/facebook.mjs.map +1 -0
- package/dist/social-providers/figma.d.mts +64 -0
- package/dist/social-providers/figma.mjs +87 -0
- package/dist/social-providers/figma.mjs.map +1 -0
- package/dist/social-providers/github.d.mts +105 -0
- package/dist/social-providers/github.mjs +97 -0
- package/dist/social-providers/github.mjs.map +1 -0
- package/dist/social-providers/gitlab.d.mts +126 -0
- package/dist/social-providers/gitlab.mjs +83 -0
- package/dist/social-providers/gitlab.mjs.map +1 -0
- package/dist/social-providers/google.d.mts +100 -0
- package/dist/social-providers/google.mjs +113 -0
- package/dist/social-providers/google.mjs.map +1 -0
- package/dist/social-providers/huggingface.d.mts +86 -0
- package/dist/social-providers/huggingface.mjs +76 -0
- package/dist/social-providers/huggingface.mjs.map +1 -0
- package/dist/social-providers/index.d.mts +1777 -2
- package/dist/social-providers/index.mjs +37 -2570
- package/dist/social-providers/index.mjs.map +1 -0
- package/dist/social-providers/kakao.d.mts +164 -0
- package/dist/social-providers/kakao.mjs +73 -0
- package/dist/social-providers/kakao.mjs.map +1 -0
- package/dist/social-providers/kick.d.mts +76 -0
- package/dist/social-providers/kick.mjs +72 -0
- package/dist/social-providers/kick.mjs.map +1 -0
- package/dist/social-providers/line.d.mts +108 -0
- package/dist/social-providers/line.mjs +114 -0
- package/dist/social-providers/line.mjs.map +1 -0
- package/dist/social-providers/linear.d.mts +71 -0
- package/dist/social-providers/linear.mjs +89 -0
- package/dist/social-providers/linear.mjs.map +1 -0
- package/dist/social-providers/linkedin.d.mts +70 -0
- package/dist/social-providers/linkedin.mjs +77 -0
- package/dist/social-providers/linkedin.mjs.map +1 -0
- package/dist/social-providers/microsoft-entra-id.d.mts +177 -0
- package/dist/social-providers/microsoft-entra-id.mjs +140 -0
- package/dist/social-providers/microsoft-entra-id.mjs.map +1 -0
- package/dist/social-providers/naver.d.mts +95 -0
- package/dist/social-providers/naver.mjs +68 -0
- package/dist/social-providers/naver.mjs.map +1 -0
- package/dist/social-providers/notion.d.mts +67 -0
- package/dist/social-providers/notion.mjs +76 -0
- package/dist/social-providers/notion.mjs.map +1 -0
- package/dist/social-providers/paybin.d.mts +74 -0
- package/dist/social-providers/paybin.mjs +86 -0
- package/dist/social-providers/paybin.mjs.map +1 -0
- package/dist/social-providers/paypal.d.mts +132 -0
- package/dist/social-providers/paypal.mjs +145 -0
- package/dist/social-providers/paypal.mjs.map +1 -0
- package/dist/social-providers/polar.d.mts +77 -0
- package/dist/social-providers/polar.mjs +74 -0
- package/dist/social-providers/polar.mjs.map +1 -0
- package/dist/social-providers/railway.d.mts +68 -0
- package/dist/social-providers/railway.mjs +78 -0
- package/dist/social-providers/railway.mjs.map +1 -0
- package/dist/social-providers/reddit.d.mts +65 -0
- package/dist/social-providers/reddit.mjs +84 -0
- package/dist/social-providers/reddit.mjs.map +1 -0
- package/dist/social-providers/roblox.d.mts +73 -0
- package/dist/social-providers/roblox.mjs +60 -0
- package/dist/social-providers/roblox.mjs.map +1 -0
- package/dist/social-providers/salesforce.d.mts +82 -0
- package/dist/social-providers/salesforce.mjs +92 -0
- package/dist/social-providers/salesforce.mjs.map +1 -0
- package/dist/social-providers/slack.d.mts +86 -0
- package/dist/social-providers/slack.mjs +69 -0
- package/dist/social-providers/slack.mjs.map +1 -0
- package/dist/social-providers/spotify.d.mts +66 -0
- package/dist/social-providers/spotify.mjs +72 -0
- package/dist/social-providers/spotify.mjs.map +1 -0
- package/dist/social-providers/tiktok.d.mts +171 -0
- package/dist/social-providers/tiktok.mjs +63 -0
- package/dist/social-providers/tiktok.mjs.map +1 -0
- package/dist/social-providers/twitch.d.mts +82 -0
- package/dist/social-providers/twitch.mjs +79 -0
- package/dist/social-providers/twitch.mjs.map +1 -0
- package/dist/social-providers/twitter.d.mts +129 -0
- package/dist/social-providers/twitter.mjs +88 -0
- package/dist/social-providers/twitter.mjs.map +1 -0
- package/dist/social-providers/vercel.d.mts +65 -0
- package/dist/social-providers/vercel.mjs +62 -0
- package/dist/social-providers/vercel.mjs.map +1 -0
- package/dist/social-providers/vk.d.mts +73 -0
- package/dist/social-providers/vk.mjs +84 -0
- package/dist/social-providers/vk.mjs.map +1 -0
- package/dist/social-providers/zoom.d.mts +166 -0
- package/dist/social-providers/zoom.mjs +73 -0
- package/dist/social-providers/zoom.mjs.map +1 -0
- package/dist/types/context.d.mts +274 -0
- package/dist/types/cookie.d.mts +16 -0
- package/dist/types/helper.d.mts +11 -0
- package/dist/types/index.d.mts +8 -0
- package/dist/types/init-options.d.mts +1298 -0
- package/dist/types/plugin-client.d.mts +113 -0
- package/dist/types/plugin.d.mts +125 -0
- package/dist/utils/db.d.mts +12 -0
- package/dist/utils/db.mjs +17 -0
- package/dist/utils/db.mjs.map +1 -0
- package/dist/utils/deprecate.d.mts +10 -0
- package/dist/utils/deprecate.mjs +18 -0
- package/dist/utils/deprecate.mjs.map +1 -0
- package/dist/utils/{index.d.mts → error-codes.d.mts} +9 -16
- package/dist/utils/error-codes.mjs +12 -0
- package/dist/utils/error-codes.mjs.map +1 -0
- package/dist/utils/id.d.mts +5 -0
- package/dist/utils/id.mjs +10 -0
- package/dist/utils/id.mjs.map +1 -0
- package/dist/utils/ip.d.mts +55 -0
- package/dist/utils/ip.mjs +119 -0
- package/dist/utils/ip.mjs.map +1 -0
- package/dist/utils/json.d.mts +5 -0
- package/dist/utils/json.mjs +26 -0
- package/dist/utils/json.mjs.map +1 -0
- package/dist/utils/string.d.mts +5 -0
- package/dist/utils/string.mjs +8 -0
- package/dist/utils/string.mjs.map +1 -0
- package/dist/utils/url.d.mts +21 -0
- package/dist/utils/url.mjs +33 -0
- package/dist/utils/url.mjs.map +1 -0
- package/package.json +36 -18
- package/src/context/endpoint-context.ts +7 -6
- package/src/context/global.ts +57 -0
- package/src/context/index.ts +2 -0
- package/src/context/request-state.ts +7 -6
- package/src/context/transaction.ts +77 -14
- package/src/db/adapter/factory.ts +54 -86
- package/src/db/adapter/get-default-model-name.ts +1 -1
- package/src/db/adapter/get-id-field.ts +4 -6
- package/src/db/adapter/index.ts +20 -15
- package/src/db/adapter/types.ts +2 -41
- package/src/db/get-tables.ts +54 -37
- package/src/db/index.ts +30 -5
- package/src/db/schema/account.ts +16 -3
- package/src/db/schema/rate-limit.ts +16 -1
- package/src/db/schema/session.ts +15 -3
- package/src/db/schema/user.ts +15 -3
- package/src/db/schema/verification.ts +16 -3
- package/src/db/test/get-tables.test.ts +33 -0
- package/src/db/type.ts +154 -1
- package/src/env/env-impl.ts +2 -2
- package/src/env/logger.ts +1 -1
- package/src/error/codes.ts +18 -1
- package/src/error/index.ts +2 -3
- package/src/oauth2/client-credentials-token.ts +26 -2
- package/src/oauth2/create-authorization-url.ts +4 -2
- package/src/oauth2/index.ts +3 -0
- package/src/oauth2/oauth-provider.ts +7 -1
- package/src/oauth2/refresh-access-token.test.ts +90 -0
- package/src/oauth2/refresh-access-token.ts +37 -4
- package/src/oauth2/validate-authorization-code.ts +55 -29
- package/src/oauth2/validate-token.test.ts +229 -0
- package/src/social-providers/apple.ts +38 -29
- package/src/social-providers/cognito.ts +6 -5
- package/src/social-providers/dropbox.ts +1 -1
- package/src/social-providers/facebook.ts +3 -3
- package/src/social-providers/figma.ts +5 -3
- package/src/social-providers/github.ts +26 -4
- package/src/social-providers/gitlab.ts +2 -2
- package/src/social-providers/google.ts +18 -14
- package/src/social-providers/huggingface.ts +1 -1
- package/src/social-providers/index.ts +9 -5
- package/src/social-providers/kakao.ts +1 -1
- package/src/social-providers/line.ts +1 -1
- package/src/social-providers/microsoft-entra-id.ts +84 -1
- package/src/social-providers/naver.ts +1 -1
- package/src/social-providers/notion.ts +1 -1
- package/src/social-providers/paybin.ts +1 -5
- package/src/social-providers/polar.ts +1 -1
- package/src/social-providers/railway.ts +100 -0
- package/src/social-providers/tiktok.ts +2 -1
- package/src/social-providers/vercel.ts +1 -1
- package/src/social-providers/zoom.ts +0 -8
- package/src/types/context.ts +241 -132
- package/src/types/cookie.ts +6 -4
- package/src/types/helper.ts +9 -0
- package/src/types/index.ts +19 -2
- package/src/types/init-options.ts +301 -186
- package/src/types/plugin-client.ts +1 -0
- package/src/types/plugin.ts +11 -6
- package/src/utils/db.ts +20 -0
- package/src/utils/deprecate.test.ts +71 -0
- package/src/utils/deprecate.ts +21 -0
- package/src/utils/error-codes.ts +12 -9
- package/src/utils/ip.test.ts +255 -0
- package/src/utils/ip.ts +211 -0
- package/src/utils/url.ts +43 -0
- package/.turbo/turbo-build.log +0 -43
- package/dist/context-DblZrIwO.mjs +0 -114
- package/dist/env-DbssmzoK.mjs +0 -245
- package/dist/index-BpRqx5_q.d.mts +0 -7833
- package/dist/oauth2-BjWM15hm.mjs +0 -326
- package/dist/utils/index.mjs +0 -4
- package/dist/utils-s65Fz0OM.mjs +0 -47
- package/src/utils/index.ts +0 -4
- package/tsconfig.json +0 -7
- package/tsdown.config.ts +0 -22
- package/vitest.config.ts +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlassian.mjs","names":[],"sources":["../../src/social-providers/atlassian.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport { logger } from \"../env\";\nimport { BetterAuthError } from \"../error\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\n\nexport interface AtlassianProfile {\n\taccount_type?: string | undefined;\n\taccount_id: string;\n\temail?: string | undefined;\n\tname: string;\n\tpicture?: string | undefined;\n\tnickname?: string | undefined;\n\tlocale?: string | undefined;\n\textended_profile?:\n\t\t| {\n\t\t\t\tjob_title?: string;\n\t\t\t\torganization?: string;\n\t\t\t\tdepartment?: string;\n\t\t\t\tlocation?: string;\n\t\t }\n\t\t| undefined;\n}\nexport interface AtlassianOptions extends ProviderOptions<AtlassianProfile> {\n\tclientId: string;\n}\n\nexport const atlassian = (options: AtlassianOptions) => {\n\treturn {\n\t\tid: \"atlassian\",\n\t\tname: \"Atlassian\",\n\n\t\tasync createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {\n\t\t\tif (!options.clientId || !options.clientSecret) {\n\t\t\t\tlogger.error(\"Client Id and Secret are required for Atlassian\");\n\t\t\t\tthrow new BetterAuthError(\"CLIENT_ID_AND_SECRET_REQUIRED\");\n\t\t\t}\n\t\t\tif (!codeVerifier) {\n\t\t\t\tthrow new BetterAuthError(\"codeVerifier is required for Atlassian\");\n\t\t\t}\n\n\t\t\tconst _scopes = options.disableDefaultScope\n\t\t\t\t? []\n\t\t\t\t: [\"read:jira-user\", \"offline_access\"];\n\t\t\tif (options.scope) _scopes.push(...options.scope);\n\t\t\tif (scopes) _scopes.push(...scopes);\n\n\t\t\treturn createAuthorizationURL({\n\t\t\t\tid: \"atlassian\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://auth.atlassian.com/authorize\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\tadditionalParams: {\n\t\t\t\t\taudience: \"api.atlassian.com\",\n\t\t\t\t},\n\t\t\t\tprompt: options.prompt,\n\t\t\t});\n\t\t},\n\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://auth.atlassian.com/oauth/token\",\n\t\t\t});\n\t\t},\n\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint: \"https://auth.atlassian.com/oauth/token\",\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\n\t\t\tif (!token.accessToken) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst { data: profile } = await betterFetch<{\n\t\t\t\t\taccount_id: string;\n\t\t\t\t\tname: string;\n\t\t\t\t\temail?: string | undefined;\n\t\t\t\t\tpicture?: string | undefined;\n\t\t\t\t}>(\"https://api.atlassian.com/me\", {\n\t\t\t\t\theaders: { Authorization: `Bearer ${token.accessToken}` },\n\t\t\t\t});\n\n\t\t\t\tif (!profile) return null;\n\n\t\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\n\t\t\t\treturn {\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tid: profile.account_id,\n\t\t\t\t\t\tname: profile.name,\n\t\t\t\t\t\temail: profile.email,\n\t\t\t\t\t\timage: profile.picture,\n\t\t\t\t\t\temailVerified: false,\n\t\t\t\t\t\t...userMap,\n\t\t\t\t\t},\n\t\t\t\t\tdata: profile,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\"Failed to fetch user info from Figma:\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\n\t\toptions,\n\t} satisfies OAuthProvider<AtlassianProfile>;\n};\n"],"mappings":";;;;;;;;;;AA+BA,MAAa,aAAa,YAA8B;AACvD,QAAO;EACN,IAAI;EACJ,MAAM;EAEN,MAAM,uBAAuB,EAAE,OAAO,QAAQ,cAAc,eAAe;AAC1E,OAAI,CAAC,QAAQ,YAAY,CAAC,QAAQ,cAAc;AAC/C,WAAO,MAAM,kDAAkD;AAC/D,UAAM,IAAI,gBAAgB,gCAAgC;;AAE3D,OAAI,CAAC,aACJ,OAAM,IAAI,gBAAgB,yCAAyC;GAGpE,MAAM,UAAU,QAAQ,sBACrB,EAAE,GACF,CAAC,kBAAkB,iBAAiB;AACvC,OAAI,QAAQ,MAAO,SAAQ,KAAK,GAAG,QAAQ,MAAM;AACjD,OAAI,OAAQ,SAAQ,KAAK,GAAG,OAAO;AAEnC,UAAO,uBAAuB;IAC7B,IAAI;IACJ;IACA,uBAAuB;IACvB,QAAQ;IACR;IACA;IACA;IACA,kBAAkB,EACjB,UAAU,qBACV;IACD,QAAQ,QAAQ;IAChB,CAAC;;EAGH,2BAA2B,OAAO,EAAE,MAAM,cAAc,kBAAkB;AACzE,UAAO,0BAA0B;IAChC;IACA;IACA;IACA;IACA,eAAe;IACf,CAAC;;EAGH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;AACxB,UAAO,mBAAmB;IACzB;IACA,SAAS;KACR,UAAU,QAAQ;KAClB,cAAc,QAAQ;KACtB;IACD,eAAe;IACf,CAAC;;EAGL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;AAGlC,OAAI,CAAC,MAAM,YACV,QAAO;AAGR,OAAI;IACH,MAAM,EAAE,MAAM,YAAY,MAAM,YAK7B,gCAAgC,EAClC,SAAS,EAAE,eAAe,UAAU,MAAM,eAAe,EACzD,CAAC;AAEF,QAAI,CAAC,QAAS,QAAO;IAErB,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AAEzD,WAAO;KACN,MAAM;MACL,IAAI,QAAQ;MACZ,MAAM,QAAQ;MACd,OAAO,QAAQ;MACf,OAAO,QAAQ;MACf,eAAe;MACf,GAAG;MACH;KACD,MAAM;KACN;YACO,OAAO;AACf,WAAO,MAAM,yCAAyC,MAAM;AAC5D,WAAO;;;EAIT;EACA"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
|
|
2
|
+
import "../oauth2/index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/social-providers/cognito.d.ts
|
|
5
|
+
interface CognitoProfile {
|
|
6
|
+
sub: string;
|
|
7
|
+
email: string;
|
|
8
|
+
email_verified: boolean;
|
|
9
|
+
name: string;
|
|
10
|
+
given_name?: string | undefined;
|
|
11
|
+
family_name?: string | undefined;
|
|
12
|
+
picture?: string | undefined;
|
|
13
|
+
username?: string | undefined;
|
|
14
|
+
locale?: string | undefined;
|
|
15
|
+
phone_number?: string | undefined;
|
|
16
|
+
phone_number_verified?: boolean | undefined;
|
|
17
|
+
aud: string;
|
|
18
|
+
iss: string;
|
|
19
|
+
exp: number;
|
|
20
|
+
iat: number;
|
|
21
|
+
[key: string]: any;
|
|
22
|
+
}
|
|
23
|
+
interface CognitoOptions extends ProviderOptions<CognitoProfile> {
|
|
24
|
+
clientId: string;
|
|
25
|
+
/**
|
|
26
|
+
* The Cognito domain (e.g., "your-app.auth.us-east-1.amazoncognito.com")
|
|
27
|
+
*/
|
|
28
|
+
domain: string;
|
|
29
|
+
/**
|
|
30
|
+
* AWS region where User Pool is hosted (e.g., "us-east-1")
|
|
31
|
+
*/
|
|
32
|
+
region: string;
|
|
33
|
+
userPoolId: string;
|
|
34
|
+
requireClientSecret?: boolean | undefined;
|
|
35
|
+
}
|
|
36
|
+
declare const cognito: (options: CognitoOptions) => {
|
|
37
|
+
id: "cognito";
|
|
38
|
+
name: string;
|
|
39
|
+
createAuthorizationURL({
|
|
40
|
+
state,
|
|
41
|
+
scopes,
|
|
42
|
+
codeVerifier,
|
|
43
|
+
redirectURI
|
|
44
|
+
}: {
|
|
45
|
+
state: string;
|
|
46
|
+
codeVerifier: string;
|
|
47
|
+
scopes?: string[] | undefined;
|
|
48
|
+
redirectURI: string;
|
|
49
|
+
display?: string | undefined;
|
|
50
|
+
loginHint?: string | undefined;
|
|
51
|
+
}): Promise<URL>;
|
|
52
|
+
validateAuthorizationCode: ({
|
|
53
|
+
code,
|
|
54
|
+
codeVerifier,
|
|
55
|
+
redirectURI
|
|
56
|
+
}: {
|
|
57
|
+
code: string;
|
|
58
|
+
redirectURI: string;
|
|
59
|
+
codeVerifier?: string | undefined;
|
|
60
|
+
deviceId?: string | undefined;
|
|
61
|
+
}) => Promise<OAuth2Tokens>;
|
|
62
|
+
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
63
|
+
verifyIdToken(token: string, nonce: string | undefined): Promise<boolean>;
|
|
64
|
+
getUserInfo(token: OAuth2Tokens & {
|
|
65
|
+
user?: {
|
|
66
|
+
name?: {
|
|
67
|
+
firstName?: string;
|
|
68
|
+
lastName?: string;
|
|
69
|
+
};
|
|
70
|
+
email?: string;
|
|
71
|
+
} | undefined;
|
|
72
|
+
}): Promise<{
|
|
73
|
+
user: {
|
|
74
|
+
id: string;
|
|
75
|
+
name?: string;
|
|
76
|
+
email?: string | null;
|
|
77
|
+
image?: string;
|
|
78
|
+
emailVerified: boolean;
|
|
79
|
+
[key: string]: any;
|
|
80
|
+
};
|
|
81
|
+
data: any;
|
|
82
|
+
} | null>;
|
|
83
|
+
options: CognitoOptions;
|
|
84
|
+
};
|
|
85
|
+
declare const getCognitoPublicKey: (kid: string, region: string, userPoolId: string) => Promise<Uint8Array<ArrayBufferLike> | CryptoKey>;
|
|
86
|
+
//#endregion
|
|
87
|
+
export { CognitoOptions, CognitoProfile, cognito, getCognitoPublicKey };
|
|
88
|
+
//# sourceMappingURL=cognito.d.mts.map
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { logger } from "../env/logger.mjs";
|
|
2
|
+
import "../env/index.mjs";
|
|
3
|
+
import { APIError, BetterAuthError } from "../error/index.mjs";
|
|
4
|
+
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
5
|
+
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
6
|
+
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
7
|
+
import "../oauth2/index.mjs";
|
|
8
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
9
|
+
import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
|
|
10
|
+
|
|
11
|
+
//#region src/social-providers/cognito.ts
|
|
12
|
+
const cognito = (options) => {
|
|
13
|
+
if (!options.domain || !options.region || !options.userPoolId) {
|
|
14
|
+
logger.error("Domain, region and userPoolId are required for Amazon Cognito. Make sure to provide them in the options.");
|
|
15
|
+
throw new BetterAuthError("DOMAIN_AND_REGION_REQUIRED");
|
|
16
|
+
}
|
|
17
|
+
const cleanDomain = options.domain.replace(/^https?:\/\//, "");
|
|
18
|
+
const authorizationEndpoint = `https://${cleanDomain}/oauth2/authorize`;
|
|
19
|
+
const tokenEndpoint = `https://${cleanDomain}/oauth2/token`;
|
|
20
|
+
const userInfoEndpoint = `https://${cleanDomain}/oauth2/userinfo`;
|
|
21
|
+
return {
|
|
22
|
+
id: "cognito",
|
|
23
|
+
name: "Cognito",
|
|
24
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
25
|
+
if (!options.clientId) {
|
|
26
|
+
logger.error("ClientId is required for Amazon Cognito. Make sure to provide them in the options.");
|
|
27
|
+
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
28
|
+
}
|
|
29
|
+
if (options.requireClientSecret && !options.clientSecret) {
|
|
30
|
+
logger.error("Client Secret is required when requireClientSecret is true. Make sure to provide it in the options.");
|
|
31
|
+
throw new BetterAuthError("CLIENT_SECRET_REQUIRED");
|
|
32
|
+
}
|
|
33
|
+
const _scopes = options.disableDefaultScope ? [] : [
|
|
34
|
+
"openid",
|
|
35
|
+
"profile",
|
|
36
|
+
"email"
|
|
37
|
+
];
|
|
38
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
39
|
+
if (scopes) _scopes.push(...scopes);
|
|
40
|
+
const url = await createAuthorizationURL({
|
|
41
|
+
id: "cognito",
|
|
42
|
+
options: { ...options },
|
|
43
|
+
authorizationEndpoint,
|
|
44
|
+
scopes: _scopes,
|
|
45
|
+
state,
|
|
46
|
+
codeVerifier,
|
|
47
|
+
redirectURI,
|
|
48
|
+
prompt: options.prompt
|
|
49
|
+
});
|
|
50
|
+
const scopeValue = url.searchParams.get("scope");
|
|
51
|
+
if (scopeValue) {
|
|
52
|
+
url.searchParams.delete("scope");
|
|
53
|
+
const encodedScope = encodeURIComponent(scopeValue);
|
|
54
|
+
const urlString = url.toString();
|
|
55
|
+
const separator = urlString.includes("?") ? "&" : "?";
|
|
56
|
+
return new URL(`${urlString}${separator}scope=${encodedScope}`);
|
|
57
|
+
}
|
|
58
|
+
return url;
|
|
59
|
+
},
|
|
60
|
+
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
61
|
+
return validateAuthorizationCode({
|
|
62
|
+
code,
|
|
63
|
+
codeVerifier,
|
|
64
|
+
redirectURI,
|
|
65
|
+
options,
|
|
66
|
+
tokenEndpoint
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
|
|
70
|
+
return refreshAccessToken({
|
|
71
|
+
refreshToken,
|
|
72
|
+
options: {
|
|
73
|
+
clientId: options.clientId,
|
|
74
|
+
clientKey: options.clientKey,
|
|
75
|
+
clientSecret: options.clientSecret
|
|
76
|
+
},
|
|
77
|
+
tokenEndpoint
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
async verifyIdToken(token, nonce) {
|
|
81
|
+
if (options.disableIdTokenSignIn) return false;
|
|
82
|
+
if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
|
|
83
|
+
try {
|
|
84
|
+
const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
|
|
85
|
+
if (!kid || !jwtAlg) return false;
|
|
86
|
+
const publicKey = await getCognitoPublicKey(kid, options.region, options.userPoolId);
|
|
87
|
+
const expectedIssuer = `https://cognito-idp.${options.region}.amazonaws.com/${options.userPoolId}`;
|
|
88
|
+
const { payload: jwtClaims } = await jwtVerify(token, publicKey, {
|
|
89
|
+
algorithms: [jwtAlg],
|
|
90
|
+
issuer: expectedIssuer,
|
|
91
|
+
audience: options.clientId,
|
|
92
|
+
maxTokenAge: "1h"
|
|
93
|
+
});
|
|
94
|
+
if (nonce && jwtClaims.nonce !== nonce) return false;
|
|
95
|
+
return true;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
logger.error("Failed to verify ID token:", error);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
async getUserInfo(token) {
|
|
102
|
+
if (options.getUserInfo) return options.getUserInfo(token);
|
|
103
|
+
if (token.idToken) try {
|
|
104
|
+
const profile = decodeJwt(token.idToken);
|
|
105
|
+
if (!profile) return null;
|
|
106
|
+
const name = profile.name || profile.given_name || profile.username || "";
|
|
107
|
+
const enrichedProfile = {
|
|
108
|
+
...profile,
|
|
109
|
+
name
|
|
110
|
+
};
|
|
111
|
+
const userMap = await options.mapProfileToUser?.(enrichedProfile);
|
|
112
|
+
return {
|
|
113
|
+
user: {
|
|
114
|
+
id: profile.sub,
|
|
115
|
+
name: enrichedProfile.name,
|
|
116
|
+
email: profile.email,
|
|
117
|
+
image: profile.picture,
|
|
118
|
+
emailVerified: profile.email_verified,
|
|
119
|
+
...userMap
|
|
120
|
+
},
|
|
121
|
+
data: enrichedProfile
|
|
122
|
+
};
|
|
123
|
+
} catch (error) {
|
|
124
|
+
logger.error("Failed to decode ID token:", error);
|
|
125
|
+
}
|
|
126
|
+
if (token.accessToken) try {
|
|
127
|
+
const { data: userInfo } = await betterFetch(userInfoEndpoint, { headers: { Authorization: `Bearer ${token.accessToken}` } });
|
|
128
|
+
if (userInfo) {
|
|
129
|
+
const userMap = await options.mapProfileToUser?.(userInfo);
|
|
130
|
+
return {
|
|
131
|
+
user: {
|
|
132
|
+
id: userInfo.sub,
|
|
133
|
+
name: userInfo.name || userInfo.given_name || userInfo.username || "",
|
|
134
|
+
email: userInfo.email,
|
|
135
|
+
image: userInfo.picture,
|
|
136
|
+
emailVerified: userInfo.email_verified,
|
|
137
|
+
...userMap
|
|
138
|
+
},
|
|
139
|
+
data: userInfo
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
logger.error("Failed to fetch user info from Cognito:", error);
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
},
|
|
147
|
+
options
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
const getCognitoPublicKey = async (kid, region, userPoolId) => {
|
|
151
|
+
const COGNITO_JWKS_URI = `https://cognito-idp.${region}.amazonaws.com/${userPoolId}/.well-known/jwks.json`;
|
|
152
|
+
try {
|
|
153
|
+
const { data } = await betterFetch(COGNITO_JWKS_URI);
|
|
154
|
+
if (!data?.keys) throw new APIError("BAD_REQUEST", { message: "Keys not found" });
|
|
155
|
+
const jwk = data.keys.find((key) => key.kid === kid);
|
|
156
|
+
if (!jwk) throw new Error(`JWK with kid ${kid} not found`);
|
|
157
|
+
return await importJWK(jwk, jwk.alg);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
logger.error("Failed to fetch Cognito public key:", error);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
//#endregion
|
|
165
|
+
export { cognito, getCognitoPublicKey };
|
|
166
|
+
//# sourceMappingURL=cognito.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cognito.mjs","names":[],"sources":["../../src/social-providers/cognito.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from \"jose\";\nimport { logger } from \"../env\";\nimport { APIError, BetterAuthError } from \"../error\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\n\nexport interface CognitoProfile {\n\tsub: string;\n\temail: string;\n\temail_verified: boolean;\n\tname: string;\n\tgiven_name?: string | undefined;\n\tfamily_name?: string | undefined;\n\tpicture?: string | undefined;\n\tusername?: string | undefined;\n\tlocale?: string | undefined;\n\tphone_number?: string | undefined;\n\tphone_number_verified?: boolean | undefined;\n\taud: string;\n\tiss: string;\n\texp: number;\n\tiat: number;\n\t// Custom attributes from Cognito can be added here\n\t[key: string]: any;\n}\n\nexport interface CognitoOptions extends ProviderOptions<CognitoProfile> {\n\tclientId: string;\n\t/**\n\t * The Cognito domain (e.g., \"your-app.auth.us-east-1.amazoncognito.com\")\n\t */\n\tdomain: string;\n\t/**\n\t * AWS region where User Pool is hosted (e.g., \"us-east-1\")\n\t */\n\tregion: string;\n\tuserPoolId: string;\n\trequireClientSecret?: boolean | undefined;\n}\n\nexport const cognito = (options: CognitoOptions) => {\n\tif (!options.domain || !options.region || !options.userPoolId) {\n\t\tlogger.error(\n\t\t\t\"Domain, region and userPoolId are required for Amazon Cognito. Make sure to provide them in the options.\",\n\t\t);\n\t\tthrow new BetterAuthError(\"DOMAIN_AND_REGION_REQUIRED\");\n\t}\n\n\tconst cleanDomain = options.domain.replace(/^https?:\\/\\//, \"\");\n\tconst authorizationEndpoint = `https://${cleanDomain}/oauth2/authorize`;\n\tconst tokenEndpoint = `https://${cleanDomain}/oauth2/token`;\n\tconst userInfoEndpoint = `https://${cleanDomain}/oauth2/userinfo`;\n\n\treturn {\n\t\tid: \"cognito\",\n\t\tname: \"Cognito\",\n\t\tasync createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {\n\t\t\tif (!options.clientId) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"ClientId is required for Amazon Cognito. Make sure to provide them in the options.\",\n\t\t\t\t);\n\t\t\t\tthrow new BetterAuthError(\"CLIENT_ID_AND_SECRET_REQUIRED\");\n\t\t\t}\n\n\t\t\tif (options.requireClientSecret && !options.clientSecret) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"Client Secret is required when requireClientSecret is true. Make sure to provide it in the options.\",\n\t\t\t\t);\n\t\t\t\tthrow new BetterAuthError(\"CLIENT_SECRET_REQUIRED\");\n\t\t\t}\n\t\t\tconst _scopes = options.disableDefaultScope\n\t\t\t\t? []\n\t\t\t\t: [\"openid\", \"profile\", \"email\"];\n\t\t\tif (options.scope) _scopes.push(...options.scope);\n\t\t\tif (scopes) _scopes.push(...scopes);\n\n\t\t\tconst url = await createAuthorizationURL({\n\t\t\t\tid: \"cognito\",\n\t\t\t\toptions: {\n\t\t\t\t\t...options,\n\t\t\t\t},\n\t\t\t\tauthorizationEndpoint,\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\tprompt: options.prompt,\n\t\t\t});\n\t\t\t// AWS Cognito requires scopes to be encoded with %20 instead of +\n\t\t\t// URLSearchParams encodes spaces as + by default, so we need to fix this\n\t\t\tconst scopeValue = url.searchParams.get(\"scope\");\n\t\t\tif (scopeValue) {\n\t\t\t\turl.searchParams.delete(\"scope\");\n\t\t\t\tconst encodedScope = encodeURIComponent(scopeValue);\n\t\t\t\t// Manually append the scope with proper encoding to the URL\n\t\t\t\tconst urlString = url.toString();\n\t\t\t\tconst separator = urlString.includes(\"?\") ? \"&\" : \"?\";\n\t\t\t\treturn new URL(`${urlString}${separator}scope=${encodedScope}`);\n\t\t\t}\n\t\t\treturn url;\n\t\t},\n\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint,\n\t\t\t});\n\t\t},\n\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint,\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\tasync verifyIdToken(token, nonce) {\n\t\t\tif (options.disableIdTokenSignIn) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (options.verifyIdToken) {\n\t\t\t\treturn options.verifyIdToken(token, nonce);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst decodedHeader = decodeProtectedHeader(token);\n\t\t\t\tconst { kid, alg: jwtAlg } = decodedHeader;\n\t\t\t\tif (!kid || !jwtAlg) return false;\n\n\t\t\t\tconst publicKey = await getCognitoPublicKey(\n\t\t\t\t\tkid,\n\t\t\t\t\toptions.region,\n\t\t\t\t\toptions.userPoolId,\n\t\t\t\t);\n\t\t\t\tconst expectedIssuer = `https://cognito-idp.${options.region}.amazonaws.com/${options.userPoolId}`;\n\n\t\t\t\tconst { payload: jwtClaims } = await jwtVerify(token, publicKey, {\n\t\t\t\t\talgorithms: [jwtAlg],\n\t\t\t\t\tissuer: expectedIssuer,\n\t\t\t\t\taudience: options.clientId,\n\t\t\t\t\tmaxTokenAge: \"1h\",\n\t\t\t\t});\n\n\t\t\t\tif (nonce && jwtClaims.nonce !== nonce) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\"Failed to verify ID token:\", error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\n\t\t\tif (token.idToken) {\n\t\t\t\ttry {\n\t\t\t\t\tconst profile = decodeJwt<CognitoProfile>(token.idToken);\n\t\t\t\t\tif (!profile) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tconst name =\n\t\t\t\t\t\tprofile.name || profile.given_name || profile.username || \"\";\n\t\t\t\t\tconst enrichedProfile = {\n\t\t\t\t\t\t...profile,\n\t\t\t\t\t\tname,\n\t\t\t\t\t};\n\t\t\t\t\tconst userMap = await options.mapProfileToUser?.(enrichedProfile);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tid: profile.sub,\n\t\t\t\t\t\t\tname: enrichedProfile.name,\n\t\t\t\t\t\t\temail: profile.email,\n\t\t\t\t\t\t\timage: profile.picture,\n\t\t\t\t\t\t\temailVerified: profile.email_verified,\n\t\t\t\t\t\t\t...userMap,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdata: enrichedProfile,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to decode ID token:\", error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (token.accessToken) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { data: userInfo } = await betterFetch<CognitoProfile>(\n\t\t\t\t\t\tuserInfoEndpoint,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\tAuthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\tif (userInfo) {\n\t\t\t\t\t\tconst userMap = await options.mapProfileToUser?.(userInfo);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\tid: userInfo.sub,\n\t\t\t\t\t\t\t\tname:\n\t\t\t\t\t\t\t\t\tuserInfo.name ||\n\t\t\t\t\t\t\t\t\tuserInfo.given_name ||\n\t\t\t\t\t\t\t\t\tuserInfo.username ||\n\t\t\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\t\temail: userInfo.email,\n\t\t\t\t\t\t\t\timage: userInfo.picture,\n\t\t\t\t\t\t\t\temailVerified: userInfo.email_verified,\n\t\t\t\t\t\t\t\t...userMap,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tdata: userInfo,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to fetch user info from Cognito:\", error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\toptions,\n\t} satisfies OAuthProvider<CognitoProfile>;\n};\n\nexport const getCognitoPublicKey = async (\n\tkid: string,\n\tregion: string,\n\tuserPoolId: string,\n) => {\n\tconst COGNITO_JWKS_URI = `https://cognito-idp.${region}.amazonaws.com/${userPoolId}/.well-known/jwks.json`;\n\n\ttry {\n\t\tconst { data } = await betterFetch<{\n\t\t\tkeys: Array<{\n\t\t\t\tkid: string;\n\t\t\t\talg: string;\n\t\t\t\tkty: string;\n\t\t\t\tuse: string;\n\t\t\t\tn: string;\n\t\t\t\te: string;\n\t\t\t}>;\n\t\t}>(COGNITO_JWKS_URI);\n\n\t\tif (!data?.keys) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Keys not found\",\n\t\t\t});\n\t\t}\n\n\t\tconst jwk = data.keys.find((key) => key.kid === kid);\n\t\tif (!jwk) {\n\t\t\tthrow new Error(`JWK with kid ${kid} not found`);\n\t\t}\n\n\t\treturn await importJWK(jwk, jwk.alg);\n\t} catch (error) {\n\t\tlogger.error(\"Failed to fetch Cognito public key:\", error);\n\t\tthrow error;\n\t}\n};\n"],"mappings":";;;;;;;;;;;AA6CA,MAAa,WAAW,YAA4B;AACnD,KAAI,CAAC,QAAQ,UAAU,CAAC,QAAQ,UAAU,CAAC,QAAQ,YAAY;AAC9D,SAAO,MACN,2GACA;AACD,QAAM,IAAI,gBAAgB,6BAA6B;;CAGxD,MAAM,cAAc,QAAQ,OAAO,QAAQ,gBAAgB,GAAG;CAC9D,MAAM,wBAAwB,WAAW,YAAY;CACrD,MAAM,gBAAgB,WAAW,YAAY;CAC7C,MAAM,mBAAmB,WAAW,YAAY;AAEhD,QAAO;EACN,IAAI;EACJ,MAAM;EACN,MAAM,uBAAuB,EAAE,OAAO,QAAQ,cAAc,eAAe;AAC1E,OAAI,CAAC,QAAQ,UAAU;AACtB,WAAO,MACN,qFACA;AACD,UAAM,IAAI,gBAAgB,gCAAgC;;AAG3D,OAAI,QAAQ,uBAAuB,CAAC,QAAQ,cAAc;AACzD,WAAO,MACN,sGACA;AACD,UAAM,IAAI,gBAAgB,yBAAyB;;GAEpD,MAAM,UAAU,QAAQ,sBACrB,EAAE,GACF;IAAC;IAAU;IAAW;IAAQ;AACjC,OAAI,QAAQ,MAAO,SAAQ,KAAK,GAAG,QAAQ,MAAM;AACjD,OAAI,OAAQ,SAAQ,KAAK,GAAG,OAAO;GAEnC,MAAM,MAAM,MAAM,uBAAuB;IACxC,IAAI;IACJ,SAAS,EACR,GAAG,SACH;IACD;IACA,QAAQ;IACR;IACA;IACA;IACA,QAAQ,QAAQ;IAChB,CAAC;GAGF,MAAM,aAAa,IAAI,aAAa,IAAI,QAAQ;AAChD,OAAI,YAAY;AACf,QAAI,aAAa,OAAO,QAAQ;IAChC,MAAM,eAAe,mBAAmB,WAAW;IAEnD,MAAM,YAAY,IAAI,UAAU;IAChC,MAAM,YAAY,UAAU,SAAS,IAAI,GAAG,MAAM;AAClD,WAAO,IAAI,IAAI,GAAG,YAAY,UAAU,QAAQ,eAAe;;AAEhE,UAAO;;EAGR,2BAA2B,OAAO,EAAE,MAAM,cAAc,kBAAkB;AACzE,UAAO,0BAA0B;IAChC;IACA;IACA;IACA;IACA;IACA,CAAC;;EAGH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;AACxB,UAAO,mBAAmB;IACzB;IACA,SAAS;KACR,UAAU,QAAQ;KAClB,WAAW,QAAQ;KACnB,cAAc,QAAQ;KACtB;IACD;IACA,CAAC;;EAGL,MAAM,cAAc,OAAO,OAAO;AACjC,OAAI,QAAQ,qBACX,QAAO;AAER,OAAI,QAAQ,cACX,QAAO,QAAQ,cAAc,OAAO,MAAM;AAG3C,OAAI;IAEH,MAAM,EAAE,KAAK,KAAK,WADI,sBAAsB,MAAM;AAElD,QAAI,CAAC,OAAO,CAAC,OAAQ,QAAO;IAE5B,MAAM,YAAY,MAAM,oBACvB,KACA,QAAQ,QACR,QAAQ,WACR;IACD,MAAM,iBAAiB,uBAAuB,QAAQ,OAAO,iBAAiB,QAAQ;IAEtF,MAAM,EAAE,SAAS,cAAc,MAAM,UAAU,OAAO,WAAW;KAChE,YAAY,CAAC,OAAO;KACpB,QAAQ;KACR,UAAU,QAAQ;KAClB,aAAa;KACb,CAAC;AAEF,QAAI,SAAS,UAAU,UAAU,MAChC,QAAO;AAER,WAAO;YACC,OAAO;AACf,WAAO,MAAM,8BAA8B,MAAM;AACjD,WAAO;;;EAIT,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;AAGlC,OAAI,MAAM,QACT,KAAI;IACH,MAAM,UAAU,UAA0B,MAAM,QAAQ;AACxD,QAAI,CAAC,QACJ,QAAO;IAER,MAAM,OACL,QAAQ,QAAQ,QAAQ,cAAc,QAAQ,YAAY;IAC3D,MAAM,kBAAkB;KACvB,GAAG;KACH;KACA;IACD,MAAM,UAAU,MAAM,QAAQ,mBAAmB,gBAAgB;AAEjE,WAAO;KACN,MAAM;MACL,IAAI,QAAQ;MACZ,MAAM,gBAAgB;MACtB,OAAO,QAAQ;MACf,OAAO,QAAQ;MACf,eAAe,QAAQ;MACvB,GAAG;MACH;KACD,MAAM;KACN;YACO,OAAO;AACf,WAAO,MAAM,8BAA8B,MAAM;;AAInD,OAAI,MAAM,YACT,KAAI;IACH,MAAM,EAAE,MAAM,aAAa,MAAM,YAChC,kBACA,EACC,SAAS,EACR,eAAe,UAAU,MAAM,eAC/B,EACD,CACD;AAED,QAAI,UAAU;KACb,MAAM,UAAU,MAAM,QAAQ,mBAAmB,SAAS;AAC1D,YAAO;MACN,MAAM;OACL,IAAI,SAAS;OACb,MACC,SAAS,QACT,SAAS,cACT,SAAS,YACT;OACD,OAAO,SAAS;OAChB,OAAO,SAAS;OAChB,eAAe,SAAS;OACxB,GAAG;OACH;MACD,MAAM;MACN;;YAEM,OAAO;AACf,WAAO,MAAM,2CAA2C,MAAM;;AAIhE,UAAO;;EAGR;EACA;;AAGF,MAAa,sBAAsB,OAClC,KACA,QACA,eACI;CACJ,MAAM,mBAAmB,uBAAuB,OAAO,iBAAiB,WAAW;AAEnF,KAAI;EACH,MAAM,EAAE,SAAS,MAAM,YASpB,iBAAiB;AAEpB,MAAI,CAAC,MAAM,KACV,OAAM,IAAI,SAAS,eAAe,EACjC,SAAS,kBACT,CAAC;EAGH,MAAM,MAAM,KAAK,KAAK,MAAM,QAAQ,IAAI,QAAQ,IAAI;AACpD,MAAI,CAAC,IACJ,OAAM,IAAI,MAAM,gBAAgB,IAAI,YAAY;AAGjD,SAAO,MAAM,UAAU,KAAK,IAAI,IAAI;UAC5B,OAAO;AACf,SAAO,MAAM,uCAAuC,MAAM;AAC1D,QAAM"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
|
|
2
|
+
import "../oauth2/index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/social-providers/discord.d.ts
|
|
5
|
+
interface DiscordProfile extends Record<string, any> {
|
|
6
|
+
/** the user's id (i.e. the numerical snowflake) */
|
|
7
|
+
id: string;
|
|
8
|
+
/** the user's username, not unique across the platform */
|
|
9
|
+
username: string;
|
|
10
|
+
/** the user's Discord-tag */
|
|
11
|
+
discriminator: string;
|
|
12
|
+
/** the user's display name, if it is set */
|
|
13
|
+
global_name: string | null;
|
|
14
|
+
/**
|
|
15
|
+
* the user's avatar hash:
|
|
16
|
+
* https://discord.com/developers/docs/reference#image-formatting
|
|
17
|
+
*/
|
|
18
|
+
avatar: string | null;
|
|
19
|
+
/** whether the user belongs to an OAuth2 application */
|
|
20
|
+
bot?: boolean | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* whether the user is an Official Discord System user (part of the urgent
|
|
23
|
+
* message system)
|
|
24
|
+
*/
|
|
25
|
+
system?: boolean | undefined;
|
|
26
|
+
/** whether the user has two factor enabled on their account */
|
|
27
|
+
mfa_enabled: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* the user's banner hash:
|
|
30
|
+
* https://discord.com/developers/docs/reference#image-formatting
|
|
31
|
+
*/
|
|
32
|
+
banner: string | null;
|
|
33
|
+
/** the user's banner color encoded as an integer representation of hexadecimal color code */
|
|
34
|
+
accent_color: number | null;
|
|
35
|
+
/**
|
|
36
|
+
* the user's chosen language option:
|
|
37
|
+
* https://discord.com/developers/docs/reference#locales
|
|
38
|
+
*/
|
|
39
|
+
locale: string;
|
|
40
|
+
/** whether the email on this account has been verified */
|
|
41
|
+
verified: boolean;
|
|
42
|
+
/** the user's email */
|
|
43
|
+
email: string;
|
|
44
|
+
/**
|
|
45
|
+
* the flags on a user's account:
|
|
46
|
+
* https://discord.com/developers/docs/resources/user#user-object-user-flags
|
|
47
|
+
*/
|
|
48
|
+
flags: number;
|
|
49
|
+
/**
|
|
50
|
+
* the type of Nitro subscription on a user's account:
|
|
51
|
+
* https://discord.com/developers/docs/resources/user#user-object-premium-types
|
|
52
|
+
*/
|
|
53
|
+
premium_type: number;
|
|
54
|
+
/**
|
|
55
|
+
* the public flags on a user's account:
|
|
56
|
+
* https://discord.com/developers/docs/resources/user#user-object-user-flags
|
|
57
|
+
*/
|
|
58
|
+
public_flags: number;
|
|
59
|
+
/** undocumented field; corresponds to the user's custom nickname */
|
|
60
|
+
display_name: string | null;
|
|
61
|
+
/**
|
|
62
|
+
* undocumented field; corresponds to the Discord feature where you can e.g.
|
|
63
|
+
* put your avatar inside of an ice cube
|
|
64
|
+
*/
|
|
65
|
+
avatar_decoration: string | null;
|
|
66
|
+
/**
|
|
67
|
+
* undocumented field; corresponds to the premium feature where you can
|
|
68
|
+
* select a custom banner color
|
|
69
|
+
*/
|
|
70
|
+
banner_color: string | null;
|
|
71
|
+
/** undocumented field; the CDN URL of their profile picture */
|
|
72
|
+
image_url: string;
|
|
73
|
+
}
|
|
74
|
+
interface DiscordOptions extends ProviderOptions<DiscordProfile> {
|
|
75
|
+
clientId: string;
|
|
76
|
+
prompt?: ("none" | "consent") | undefined;
|
|
77
|
+
permissions?: number | undefined;
|
|
78
|
+
}
|
|
79
|
+
declare const discord: (options: DiscordOptions) => {
|
|
80
|
+
id: "discord";
|
|
81
|
+
name: string;
|
|
82
|
+
createAuthorizationURL({
|
|
83
|
+
state,
|
|
84
|
+
scopes,
|
|
85
|
+
redirectURI
|
|
86
|
+
}: {
|
|
87
|
+
state: string;
|
|
88
|
+
codeVerifier: string;
|
|
89
|
+
scopes?: string[] | undefined;
|
|
90
|
+
redirectURI: string;
|
|
91
|
+
display?: string | undefined;
|
|
92
|
+
loginHint?: string | undefined;
|
|
93
|
+
}): URL;
|
|
94
|
+
validateAuthorizationCode: ({
|
|
95
|
+
code,
|
|
96
|
+
redirectURI
|
|
97
|
+
}: {
|
|
98
|
+
code: string;
|
|
99
|
+
redirectURI: string;
|
|
100
|
+
codeVerifier?: string | undefined;
|
|
101
|
+
deviceId?: string | undefined;
|
|
102
|
+
}) => Promise<OAuth2Tokens>;
|
|
103
|
+
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
104
|
+
getUserInfo(token: OAuth2Tokens & {
|
|
105
|
+
user?: {
|
|
106
|
+
name?: {
|
|
107
|
+
firstName?: string;
|
|
108
|
+
lastName?: string;
|
|
109
|
+
};
|
|
110
|
+
email?: string;
|
|
111
|
+
} | undefined;
|
|
112
|
+
}): Promise<{
|
|
113
|
+
user: {
|
|
114
|
+
id: string;
|
|
115
|
+
name?: string;
|
|
116
|
+
email?: string | null;
|
|
117
|
+
image?: string;
|
|
118
|
+
emailVerified: boolean;
|
|
119
|
+
[key: string]: any;
|
|
120
|
+
};
|
|
121
|
+
data: any;
|
|
122
|
+
} | null>;
|
|
123
|
+
options: DiscordOptions;
|
|
124
|
+
};
|
|
125
|
+
//#endregion
|
|
126
|
+
export { DiscordOptions, DiscordProfile, discord };
|
|
127
|
+
//# sourceMappingURL=discord.d.mts.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
2
|
+
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
3
|
+
import "../oauth2/index.mjs";
|
|
4
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
5
|
+
|
|
6
|
+
//#region src/social-providers/discord.ts
|
|
7
|
+
const discord = (options) => {
|
|
8
|
+
return {
|
|
9
|
+
id: "discord",
|
|
10
|
+
name: "Discord",
|
|
11
|
+
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
12
|
+
const _scopes = options.disableDefaultScope ? [] : ["identify", "email"];
|
|
13
|
+
if (scopes) _scopes.push(...scopes);
|
|
14
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
15
|
+
const permissionsParam = _scopes.includes("bot") && options.permissions !== void 0 ? `&permissions=${options.permissions}` : "";
|
|
16
|
+
return new URL(`https://discord.com/api/oauth2/authorize?scope=${_scopes.join("+")}&response_type=code&client_id=${options.clientId}&redirect_uri=${encodeURIComponent(options.redirectURI || redirectURI)}&state=${state}&prompt=${options.prompt || "none"}${permissionsParam}`);
|
|
17
|
+
},
|
|
18
|
+
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
19
|
+
return validateAuthorizationCode({
|
|
20
|
+
code,
|
|
21
|
+
redirectURI,
|
|
22
|
+
options,
|
|
23
|
+
tokenEndpoint: "https://discord.com/api/oauth2/token"
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
|
|
27
|
+
return refreshAccessToken({
|
|
28
|
+
refreshToken,
|
|
29
|
+
options: {
|
|
30
|
+
clientId: options.clientId,
|
|
31
|
+
clientKey: options.clientKey,
|
|
32
|
+
clientSecret: options.clientSecret
|
|
33
|
+
},
|
|
34
|
+
tokenEndpoint: "https://discord.com/api/oauth2/token"
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
async getUserInfo(token) {
|
|
38
|
+
if (options.getUserInfo) return options.getUserInfo(token);
|
|
39
|
+
const { data: profile, error } = await betterFetch("https://discord.com/api/users/@me", { headers: { authorization: `Bearer ${token.accessToken}` } });
|
|
40
|
+
if (error) return null;
|
|
41
|
+
if (profile.avatar === null) profile.image_url = `https://cdn.discordapp.com/embed/avatars/${profile.discriminator === "0" ? Number(BigInt(profile.id) >> BigInt(22)) % 6 : parseInt(profile.discriminator) % 5}.png`;
|
|
42
|
+
else {
|
|
43
|
+
const format = profile.avatar.startsWith("a_") ? "gif" : "png";
|
|
44
|
+
profile.image_url = `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;
|
|
45
|
+
}
|
|
46
|
+
const userMap = await options.mapProfileToUser?.(profile);
|
|
47
|
+
return {
|
|
48
|
+
user: {
|
|
49
|
+
id: profile.id,
|
|
50
|
+
name: profile.global_name || profile.username || "",
|
|
51
|
+
email: profile.email,
|
|
52
|
+
emailVerified: profile.verified,
|
|
53
|
+
image: profile.image_url,
|
|
54
|
+
...userMap
|
|
55
|
+
},
|
|
56
|
+
data: profile
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
options
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { discord };
|
|
65
|
+
//# sourceMappingURL=discord.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord.mjs","names":[],"sources":["../../src/social-providers/discord.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport { refreshAccessToken, validateAuthorizationCode } from \"../oauth2\";\nexport interface DiscordProfile extends Record<string, any> {\n\t/** the user's id (i.e. the numerical snowflake) */\n\tid: string;\n\t/** the user's username, not unique across the platform */\n\tusername: string;\n\t/** the user's Discord-tag */\n\tdiscriminator: string;\n\t/** the user's display name, if it is set */\n\tglobal_name: string | null;\n\t/**\n\t * the user's avatar hash:\n\t * https://discord.com/developers/docs/reference#image-formatting\n\t */\n\tavatar: string | null;\n\t/** whether the user belongs to an OAuth2 application */\n\tbot?: boolean | undefined;\n\t/**\n\t * whether the user is an Official Discord System user (part of the urgent\n\t * message system)\n\t */\n\tsystem?: boolean | undefined;\n\t/** whether the user has two factor enabled on their account */\n\tmfa_enabled: boolean;\n\t/**\n\t * the user's banner hash:\n\t * https://discord.com/developers/docs/reference#image-formatting\n\t */\n\tbanner: string | null;\n\n\t/** the user's banner color encoded as an integer representation of hexadecimal color code */\n\taccent_color: number | null;\n\n\t/**\n\t * the user's chosen language option:\n\t * https://discord.com/developers/docs/reference#locales\n\t */\n\tlocale: string;\n\t/** whether the email on this account has been verified */\n\tverified: boolean;\n\t/** the user's email */\n\temail: string;\n\t/**\n\t * the flags on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-user-flags\n\t */\n\tflags: number;\n\t/**\n\t * the type of Nitro subscription on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-premium-types\n\t */\n\tpremium_type: number;\n\t/**\n\t * the public flags on a user's account:\n\t * https://discord.com/developers/docs/resources/user#user-object-user-flags\n\t */\n\tpublic_flags: number;\n\t/** undocumented field; corresponds to the user's custom nickname */\n\tdisplay_name: string | null;\n\t/**\n\t * undocumented field; corresponds to the Discord feature where you can e.g.\n\t * put your avatar inside of an ice cube\n\t */\n\tavatar_decoration: string | null;\n\t/**\n\t * undocumented field; corresponds to the premium feature where you can\n\t * select a custom banner color\n\t */\n\tbanner_color: string | null;\n\t/** undocumented field; the CDN URL of their profile picture */\n\timage_url: string;\n}\n\nexport interface DiscordOptions extends ProviderOptions<DiscordProfile> {\n\tclientId: string;\n\tprompt?: (\"none\" | \"consent\") | undefined;\n\tpermissions?: number | undefined;\n}\n\nexport const discord = (options: DiscordOptions) => {\n\treturn {\n\t\tid: \"discord\",\n\t\tname: \"Discord\",\n\t\tcreateAuthorizationURL({ state, scopes, redirectURI }) {\n\t\t\tconst _scopes = options.disableDefaultScope ? [] : [\"identify\", \"email\"];\n\t\t\tif (scopes) _scopes.push(...scopes);\n\t\t\tif (options.scope) _scopes.push(...options.scope);\n\t\t\tconst hasBotScope = _scopes.includes(\"bot\");\n\t\t\tconst permissionsParam =\n\t\t\t\thasBotScope && options.permissions !== undefined\n\t\t\t\t\t? `&permissions=${options.permissions}`\n\t\t\t\t\t: \"\";\n\t\t\treturn new URL(\n\t\t\t\t`https://discord.com/api/oauth2/authorize?scope=${_scopes.join(\n\t\t\t\t\t\"+\",\n\t\t\t\t)}&response_type=code&client_id=${\n\t\t\t\t\toptions.clientId\n\t\t\t\t}&redirect_uri=${encodeURIComponent(\n\t\t\t\t\toptions.redirectURI || redirectURI,\n\t\t\t\t)}&state=${state}&prompt=${\n\t\t\t\t\toptions.prompt || \"none\"\n\t\t\t\t}${permissionsParam}`,\n\t\t\t);\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://discord.com/api/oauth2/token\",\n\t\t\t});\n\t\t},\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint: \"https://discord.com/api/oauth2/token\",\n\t\t\t\t\t});\n\t\t\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\t\t\tconst { data: profile, error } = await betterFetch<DiscordProfile>(\n\t\t\t\t\"https://discord.com/api/users/@me\",\n\t\t\t\t{\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tauthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (profile.avatar === null) {\n\t\t\t\tconst defaultAvatarNumber =\n\t\t\t\t\tprofile.discriminator === \"0\"\n\t\t\t\t\t\t? Number(BigInt(profile.id) >> BigInt(22)) % 6\n\t\t\t\t\t\t: parseInt(profile.discriminator) % 5;\n\t\t\t\tprofile.image_url = `https://cdn.discordapp.com/embed/avatars/${defaultAvatarNumber}.png`;\n\t\t\t} else {\n\t\t\t\tconst format = profile.avatar.startsWith(\"a_\") ? \"gif\" : \"png\";\n\t\t\t\tprofile.image_url = `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;\n\t\t\t}\n\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.id,\n\t\t\t\t\tname: profile.global_name || profile.username || \"\",\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\temailVerified: profile.verified,\n\t\t\t\t\timage: profile.image_url,\n\t\t\t\t\t...userMap,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t\toptions,\n\t} satisfies OAuthProvider<DiscordProfile>;\n};\n"],"mappings":";;;;;;AAiFA,MAAa,WAAW,YAA4B;AACnD,QAAO;EACN,IAAI;EACJ,MAAM;EACN,uBAAuB,EAAE,OAAO,QAAQ,eAAe;GACtD,MAAM,UAAU,QAAQ,sBAAsB,EAAE,GAAG,CAAC,YAAY,QAAQ;AACxE,OAAI,OAAQ,SAAQ,KAAK,GAAG,OAAO;AACnC,OAAI,QAAQ,MAAO,SAAQ,KAAK,GAAG,QAAQ,MAAM;GAEjD,MAAM,mBADc,QAAQ,SAAS,MAAM,IAE3B,QAAQ,gBAAgB,SACpC,gBAAgB,QAAQ,gBACxB;AACJ,UAAO,IAAI,IACV,kDAAkD,QAAQ,KACzD,IACA,CAAC,gCACD,QAAQ,SACR,gBAAgB,mBAChB,QAAQ,eAAe,YACvB,CAAC,SAAS,MAAM,UAChB,QAAQ,UAAU,SAChB,mBACH;;EAEF,2BAA2B,OAAO,EAAE,MAAM,kBAAkB;AAC3D,UAAO,0BAA0B;IAChC;IACA;IACA;IACA,eAAe;IACf,CAAC;;EAEH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;AACxB,UAAO,mBAAmB;IACzB;IACA,SAAS;KACR,UAAU,QAAQ;KAClB,WAAW,QAAQ;KACnB,cAAc,QAAQ;KACtB;IACD,eAAe;IACf,CAAC;;EAEL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;GAElC,MAAM,EAAE,MAAM,SAAS,UAAU,MAAM,YACtC,qCACA,EACC,SAAS,EACR,eAAe,UAAU,MAAM,eAC/B,EACD,CACD;AAED,OAAI,MACH,QAAO;AAER,OAAI,QAAQ,WAAW,KAKtB,SAAQ,YAAY,4CAHnB,QAAQ,kBAAkB,MACvB,OAAO,OAAO,QAAQ,GAAG,IAAI,OAAO,GAAG,CAAC,GAAG,IAC3C,SAAS,QAAQ,cAAc,GAAG,EAC8C;QAC9E;IACN,MAAM,SAAS,QAAQ,OAAO,WAAW,KAAK,GAAG,QAAQ;AACzD,YAAQ,YAAY,sCAAsC,QAAQ,GAAG,GAAG,QAAQ,OAAO,GAAG;;GAE3F,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AACzD,UAAO;IACN,MAAM;KACL,IAAI,QAAQ;KACZ,MAAM,QAAQ,eAAe,QAAQ,YAAY;KACjD,OAAO,QAAQ;KACf,eAAe,QAAQ;KACvB,OAAO,QAAQ;KACf,GAAG;KACH;IACD,MAAM;IACN;;EAEF;EACA"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
|
|
2
|
+
import "../oauth2/index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/social-providers/dropbox.d.ts
|
|
5
|
+
interface DropboxProfile {
|
|
6
|
+
account_id: string;
|
|
7
|
+
name: {
|
|
8
|
+
given_name: string;
|
|
9
|
+
surname: string;
|
|
10
|
+
familiar_name: string;
|
|
11
|
+
display_name: string;
|
|
12
|
+
abbreviated_name: string;
|
|
13
|
+
};
|
|
14
|
+
email: string;
|
|
15
|
+
email_verified: boolean;
|
|
16
|
+
profile_photo_url: string;
|
|
17
|
+
}
|
|
18
|
+
interface DropboxOptions extends ProviderOptions<DropboxProfile> {
|
|
19
|
+
clientId: string;
|
|
20
|
+
accessType?: ("offline" | "online" | "legacy") | undefined;
|
|
21
|
+
}
|
|
22
|
+
declare const dropbox: (options: DropboxOptions) => {
|
|
23
|
+
id: "dropbox";
|
|
24
|
+
name: string;
|
|
25
|
+
createAuthorizationURL: ({
|
|
26
|
+
state,
|
|
27
|
+
scopes,
|
|
28
|
+
codeVerifier,
|
|
29
|
+
redirectURI
|
|
30
|
+
}: {
|
|
31
|
+
state: string;
|
|
32
|
+
codeVerifier: string;
|
|
33
|
+
scopes?: string[] | undefined;
|
|
34
|
+
redirectURI: string;
|
|
35
|
+
display?: string | undefined;
|
|
36
|
+
loginHint?: string | undefined;
|
|
37
|
+
}) => Promise<URL>;
|
|
38
|
+
validateAuthorizationCode: ({
|
|
39
|
+
code,
|
|
40
|
+
codeVerifier,
|
|
41
|
+
redirectURI
|
|
42
|
+
}: {
|
|
43
|
+
code: string;
|
|
44
|
+
redirectURI: string;
|
|
45
|
+
codeVerifier?: string | undefined;
|
|
46
|
+
deviceId?: string | undefined;
|
|
47
|
+
}) => Promise<OAuth2Tokens>;
|
|
48
|
+
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
49
|
+
getUserInfo(token: OAuth2Tokens & {
|
|
50
|
+
user?: {
|
|
51
|
+
name?: {
|
|
52
|
+
firstName?: string;
|
|
53
|
+
lastName?: string;
|
|
54
|
+
};
|
|
55
|
+
email?: string;
|
|
56
|
+
} | undefined;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
user: {
|
|
59
|
+
id: string;
|
|
60
|
+
name?: string;
|
|
61
|
+
email?: string | null;
|
|
62
|
+
image?: string;
|
|
63
|
+
emailVerified: boolean;
|
|
64
|
+
[key: string]: any;
|
|
65
|
+
};
|
|
66
|
+
data: any;
|
|
67
|
+
} | null>;
|
|
68
|
+
options: DropboxOptions;
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
export { DropboxOptions, DropboxProfile, dropbox };
|
|
72
|
+
//# sourceMappingURL=dropbox.d.mts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
2
|
+
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
3
|
+
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
4
|
+
import "../oauth2/index.mjs";
|
|
5
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
6
|
+
|
|
7
|
+
//#region src/social-providers/dropbox.ts
|
|
8
|
+
const dropbox = (options) => {
|
|
9
|
+
const tokenEndpoint = "https://api.dropboxapi.com/oauth2/token";
|
|
10
|
+
return {
|
|
11
|
+
id: "dropbox",
|
|
12
|
+
name: "Dropbox",
|
|
13
|
+
createAuthorizationURL: async ({ state, scopes, codeVerifier, redirectURI }) => {
|
|
14
|
+
const _scopes = options.disableDefaultScope ? [] : ["account_info.read"];
|
|
15
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
16
|
+
if (scopes) _scopes.push(...scopes);
|
|
17
|
+
const additionalParams = {};
|
|
18
|
+
if (options.accessType) additionalParams.token_access_type = options.accessType;
|
|
19
|
+
return await createAuthorizationURL({
|
|
20
|
+
id: "dropbox",
|
|
21
|
+
options,
|
|
22
|
+
authorizationEndpoint: "https://www.dropbox.com/oauth2/authorize",
|
|
23
|
+
scopes: _scopes,
|
|
24
|
+
state,
|
|
25
|
+
redirectURI,
|
|
26
|
+
codeVerifier,
|
|
27
|
+
additionalParams
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
31
|
+
return await validateAuthorizationCode({
|
|
32
|
+
code,
|
|
33
|
+
codeVerifier,
|
|
34
|
+
redirectURI,
|
|
35
|
+
options,
|
|
36
|
+
tokenEndpoint
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
|
|
40
|
+
return refreshAccessToken({
|
|
41
|
+
refreshToken,
|
|
42
|
+
options: {
|
|
43
|
+
clientId: options.clientId,
|
|
44
|
+
clientKey: options.clientKey,
|
|
45
|
+
clientSecret: options.clientSecret
|
|
46
|
+
},
|
|
47
|
+
tokenEndpoint
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
async getUserInfo(token) {
|
|
51
|
+
if (options.getUserInfo) return options.getUserInfo(token);
|
|
52
|
+
const { data: profile, error } = await betterFetch("https://api.dropboxapi.com/2/users/get_current_account", {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: { Authorization: `Bearer ${token.accessToken}` }
|
|
55
|
+
});
|
|
56
|
+
if (error) return null;
|
|
57
|
+
const userMap = await options.mapProfileToUser?.(profile);
|
|
58
|
+
return {
|
|
59
|
+
user: {
|
|
60
|
+
id: profile.account_id,
|
|
61
|
+
name: profile.name?.display_name,
|
|
62
|
+
email: profile.email,
|
|
63
|
+
emailVerified: profile.email_verified || false,
|
|
64
|
+
image: profile.profile_photo_url,
|
|
65
|
+
...userMap
|
|
66
|
+
},
|
|
67
|
+
data: profile
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
options
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
export { dropbox };
|
|
76
|
+
//# sourceMappingURL=dropbox.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropbox.mjs","names":[],"sources":["../../src/social-providers/dropbox.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\n\nexport interface DropboxProfile {\n\taccount_id: string;\n\tname: {\n\t\tgiven_name: string;\n\t\tsurname: string;\n\t\tfamiliar_name: string;\n\t\tdisplay_name: string;\n\t\tabbreviated_name: string;\n\t};\n\temail: string;\n\temail_verified: boolean;\n\tprofile_photo_url: string;\n}\n\nexport interface DropboxOptions extends ProviderOptions<DropboxProfile> {\n\tclientId: string;\n\taccessType?: (\"offline\" | \"online\" | \"legacy\") | undefined;\n}\n\nexport const dropbox = (options: DropboxOptions) => {\n\tconst tokenEndpoint = \"https://api.dropboxapi.com/oauth2/token\";\n\n\treturn {\n\t\tid: \"dropbox\",\n\t\tname: \"Dropbox\",\n\t\tcreateAuthorizationURL: async ({\n\t\t\tstate,\n\t\t\tscopes,\n\t\t\tcodeVerifier,\n\t\t\tredirectURI,\n\t\t}) => {\n\t\t\tconst _scopes = options.disableDefaultScope ? [] : [\"account_info.read\"];\n\t\t\tif (options.scope) _scopes.push(...options.scope);\n\t\t\tif (scopes) _scopes.push(...scopes);\n\t\t\tconst additionalParams: Record<string, string> = {};\n\t\t\tif (options.accessType) {\n\t\t\t\tadditionalParams.token_access_type = options.accessType;\n\t\t\t}\n\t\t\treturn await createAuthorizationURL({\n\t\t\t\tid: \"dropbox\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://www.dropbox.com/oauth2/authorize\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate,\n\t\t\t\tredirectURI,\n\t\t\t\tcodeVerifier,\n\t\t\t\tadditionalParams,\n\t\t\t});\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn await validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint,\n\t\t\t});\n\t\t},\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\t\t\tconst { data: profile, error } = await betterFetch<DropboxProfile>(\n\t\t\t\t\"https://api.dropboxapi.com/2/users/get_current_account\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tAuthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.account_id,\n\t\t\t\t\tname: profile.name?.display_name,\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\temailVerified: profile.email_verified || false,\n\t\t\t\t\timage: profile.profile_photo_url,\n\t\t\t\t\t...userMap,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t\toptions,\n\t} satisfies OAuthProvider<DropboxProfile>;\n};\n"],"mappings":";;;;;;;AA2BA,MAAa,WAAW,YAA4B;CACnD,MAAM,gBAAgB;AAEtB,QAAO;EACN,IAAI;EACJ,MAAM;EACN,wBAAwB,OAAO,EAC9B,OACA,QACA,cACA,kBACK;GACL,MAAM,UAAU,QAAQ,sBAAsB,EAAE,GAAG,CAAC,oBAAoB;AACxE,OAAI,QAAQ,MAAO,SAAQ,KAAK,GAAG,QAAQ,MAAM;AACjD,OAAI,OAAQ,SAAQ,KAAK,GAAG,OAAO;GACnC,MAAM,mBAA2C,EAAE;AACnD,OAAI,QAAQ,WACX,kBAAiB,oBAAoB,QAAQ;AAE9C,UAAO,MAAM,uBAAuB;IACnC,IAAI;IACJ;IACA,uBAAuB;IACvB,QAAQ;IACR;IACA;IACA;IACA;IACA,CAAC;;EAEH,2BAA2B,OAAO,EAAE,MAAM,cAAc,kBAAkB;AACzE,UAAO,MAAM,0BAA0B;IACtC;IACA;IACA;IACA;IACA;IACA,CAAC;;EAEH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;AACxB,UAAO,mBAAmB;IACzB;IACA,SAAS;KACR,UAAU,QAAQ;KAClB,WAAW,QAAQ;KACnB,cAAc,QAAQ;KACtB;IACD;IACA,CAAC;;EAEL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;GAElC,MAAM,EAAE,MAAM,SAAS,UAAU,MAAM,YACtC,0DACA;IACC,QAAQ;IACR,SAAS,EACR,eAAe,UAAU,MAAM,eAC/B;IACD,CACD;AAED,OAAI,MACH,QAAO;GAER,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AACzD,UAAO;IACN,MAAM;KACL,IAAI,QAAQ;KACZ,MAAM,QAAQ,MAAM;KACpB,OAAO,QAAQ;KACf,eAAe,QAAQ,kBAAkB;KACzC,OAAO,QAAQ;KACf,GAAG;KACH;IACD,MAAM;IACN;;EAEF;EACA"}
|