@draftlab/auth 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/allow.js +26 -0
- package/dist/esm/client.js +254 -0
- package/dist/esm/core.js +597 -0
- package/dist/esm/css.d.js +0 -0
- package/dist/esm/error.js +88 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/keys.js +126 -0
- package/dist/esm/mutex.js +53 -0
- package/dist/esm/pkce.js +87 -0
- package/dist/esm/provider/apple.js +15 -0
- package/dist/esm/provider/code.js +62 -0
- package/dist/esm/provider/discord.js +15 -0
- package/dist/esm/provider/facebook.js +15 -0
- package/dist/esm/provider/github.js +15 -0
- package/dist/esm/provider/gitlab.js +15 -0
- package/dist/esm/provider/google.js +16 -0
- package/dist/esm/provider/linkedin.js +15 -0
- package/dist/esm/provider/magiclink.js +83 -0
- package/dist/esm/provider/microsoft.js +15 -0
- package/dist/esm/provider/oauth2.js +130 -0
- package/dist/esm/provider/password.js +331 -0
- package/dist/esm/provider/provider.js +18 -0
- package/dist/esm/provider/reddit.js +15 -0
- package/dist/esm/provider/slack.js +15 -0
- package/dist/esm/provider/spotify.js +15 -0
- package/dist/esm/provider/twitch.js +15 -0
- package/dist/esm/provider/vercel.js +17 -0
- package/dist/esm/random.js +40 -0
- package/dist/esm/revocation.js +27 -0
- package/dist/esm/storage/memory.js +110 -0
- package/dist/esm/storage/storage.js +56 -0
- package/dist/esm/storage/turso.js +93 -0
- package/dist/esm/storage/unstorage.js +78 -0
- package/dist/esm/subject.js +7 -0
- package/dist/esm/themes/theme.js +115 -0
- package/dist/esm/toolkit/client.js +119 -0
- package/dist/esm/toolkit/index.js +25 -0
- package/dist/esm/toolkit/providers/facebook.js +11 -0
- package/dist/esm/toolkit/providers/github.js +11 -0
- package/dist/esm/toolkit/providers/google.js +11 -0
- package/dist/esm/toolkit/providers/strategy.js +0 -0
- package/dist/esm/toolkit/storage.js +81 -0
- package/dist/esm/toolkit/utils.js +18 -0
- package/dist/esm/types.js +0 -0
- package/dist/esm/ui/base.js +478 -0
- package/dist/esm/ui/code.js +186 -0
- package/dist/esm/ui/form.js +46 -0
- package/dist/esm/ui/icon.js +242 -0
- package/dist/esm/ui/magiclink.js +158 -0
- package/dist/esm/ui/password.js +435 -0
- package/dist/esm/ui/select.js +102 -0
- package/dist/esm/util.js +59 -0
- package/dist/{allow.d.mts → types/allow.d.ts} +9 -11
- package/dist/types/allow.d.ts.map +1 -0
- package/dist/types/client.d.ts +462 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/core.d.ts +113 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/{error.d.mts → types/error.d.ts} +95 -97
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/{keys.d.mts → types/keys.d.ts} +20 -24
- package/dist/types/keys.d.ts.map +1 -0
- package/dist/types/mutex.d.ts +42 -0
- package/dist/types/mutex.d.ts.map +1 -0
- package/dist/{pkce.d.mts → types/pkce.d.ts} +10 -11
- package/dist/types/pkce.d.ts.map +1 -0
- package/dist/types/provider/apple.d.ts +197 -0
- package/dist/types/provider/apple.d.ts.map +1 -0
- package/dist/types/provider/code.d.ts +288 -0
- package/dist/types/provider/code.d.ts.map +1 -0
- package/dist/types/provider/discord.d.ts +206 -0
- package/dist/types/provider/discord.d.ts.map +1 -0
- package/dist/types/provider/facebook.d.ts +200 -0
- package/dist/types/provider/facebook.d.ts.map +1 -0
- package/dist/types/provider/github.d.ts +220 -0
- package/dist/types/provider/github.d.ts.map +1 -0
- package/dist/types/provider/gitlab.d.ts +180 -0
- package/dist/types/provider/gitlab.d.ts.map +1 -0
- package/dist/types/provider/google.d.ts +158 -0
- package/dist/types/provider/google.d.ts.map +1 -0
- package/dist/types/provider/linkedin.d.ts +190 -0
- package/dist/types/provider/linkedin.d.ts.map +1 -0
- package/dist/types/provider/magiclink.d.ts +141 -0
- package/dist/types/provider/magiclink.d.ts.map +1 -0
- package/dist/types/provider/microsoft.d.ts +247 -0
- package/dist/types/provider/microsoft.d.ts.map +1 -0
- package/dist/types/provider/oauth2.d.ts +229 -0
- package/dist/types/provider/oauth2.d.ts.map +1 -0
- package/dist/types/provider/password.d.ts +408 -0
- package/dist/types/provider/password.d.ts.map +1 -0
- package/dist/types/provider/provider.d.ts +226 -0
- package/dist/types/provider/provider.d.ts.map +1 -0
- package/dist/types/provider/reddit.d.ts +159 -0
- package/dist/types/provider/reddit.d.ts.map +1 -0
- package/dist/types/provider/slack.d.ts +171 -0
- package/dist/types/provider/slack.d.ts.map +1 -0
- package/dist/types/provider/spotify.d.ts +168 -0
- package/dist/types/provider/spotify.d.ts.map +1 -0
- package/dist/types/provider/twitch.d.ts +163 -0
- package/dist/types/provider/twitch.d.ts.map +1 -0
- package/dist/types/provider/vercel.d.ts +294 -0
- package/dist/types/provider/vercel.d.ts.map +1 -0
- package/dist/{random.d.mts → types/random.d.ts} +4 -6
- package/dist/types/random.d.ts.map +1 -0
- package/dist/types/revocation.d.ts +76 -0
- package/dist/types/revocation.d.ts.map +1 -0
- package/dist/{storage/memory.d.mts → types/storage/memory.d.ts} +17 -21
- package/dist/types/storage/memory.d.ts.map +1 -0
- package/dist/types/storage/storage.d.ts +177 -0
- package/dist/types/storage/storage.d.ts.map +1 -0
- package/dist/{storage/turso.d.mts → types/storage/turso.d.ts} +4 -8
- package/dist/types/storage/turso.d.ts.map +1 -0
- package/dist/{storage/unstorage.d.mts → types/storage/unstorage.d.ts} +12 -11
- package/dist/types/storage/unstorage.d.ts.map +1 -0
- package/dist/types/subject.d.ts +115 -0
- package/dist/types/subject.d.ts.map +1 -0
- package/dist/types/themes/theme.d.ts +207 -0
- package/dist/types/themes/theme.d.ts.map +1 -0
- package/dist/types/toolkit/client.d.ts +235 -0
- package/dist/types/toolkit/client.d.ts.map +1 -0
- package/dist/types/toolkit/index.d.ts +45 -0
- package/dist/types/toolkit/index.d.ts.map +1 -0
- package/dist/types/toolkit/providers/facebook.d.ts +8 -0
- package/dist/types/toolkit/providers/facebook.d.ts.map +1 -0
- package/dist/types/toolkit/providers/github.d.ts +8 -0
- package/dist/types/toolkit/providers/github.d.ts.map +1 -0
- package/dist/types/toolkit/providers/google.d.ts +8 -0
- package/dist/types/toolkit/providers/google.d.ts.map +1 -0
- package/dist/types/toolkit/providers/strategy.d.ts +38 -0
- package/dist/types/toolkit/providers/strategy.d.ts.map +1 -0
- package/dist/{toolkit/storage.d.mts → types/toolkit/storage.d.ts} +37 -39
- package/dist/types/toolkit/storage.d.ts.map +1 -0
- package/dist/{toolkit/utils.d.mts → types/toolkit/utils.d.ts} +2 -4
- package/dist/types/toolkit/utils.d.ts.map +1 -0
- package/dist/types/types.d.ts +92 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/ui/base.d.ts +18 -0
- package/dist/types/ui/base.d.ts.map +1 -0
- package/dist/types/ui/code.d.ts +43 -0
- package/dist/types/ui/code.d.ts.map +1 -0
- package/dist/types/ui/form.d.ts +24 -0
- package/dist/types/ui/form.d.ts.map +1 -0
- package/dist/types/ui/icon.d.ts +60 -0
- package/dist/types/ui/icon.d.ts.map +1 -0
- package/dist/types/ui/magiclink.d.ts +41 -0
- package/dist/types/ui/magiclink.d.ts.map +1 -0
- package/dist/types/ui/password.d.ts +43 -0
- package/dist/types/ui/password.d.ts.map +1 -0
- package/dist/types/ui/select.d.ts +33 -0
- package/dist/types/ui/select.d.ts.map +1 -0
- package/dist/{util.d.mts → types/util.d.ts} +11 -13
- package/dist/types/util.d.ts.map +1 -0
- package/package.json +10 -16
- package/dist/adapters/node.d.mts +0 -18
- package/dist/adapters/node.mjs +0 -69
- package/dist/allow.mjs +0 -63
- package/dist/client.d.mts +0 -456
- package/dist/client.mjs +0 -283
- package/dist/core.d.mts +0 -110
- package/dist/core.mjs +0 -595
- package/dist/error.mjs +0 -237
- package/dist/index.d.mts +0 -2
- package/dist/index.mjs +0 -3
- package/dist/keys.mjs +0 -146
- package/dist/mutex.d.mts +0 -44
- package/dist/mutex.mjs +0 -110
- package/dist/pkce.mjs +0 -157
- package/dist/provider/apple.d.mts +0 -111
- package/dist/provider/apple.mjs +0 -164
- package/dist/provider/code.d.mts +0 -228
- package/dist/provider/code.mjs +0 -246
- package/dist/provider/discord.d.mts +0 -146
- package/dist/provider/discord.mjs +0 -156
- package/dist/provider/facebook.d.mts +0 -142
- package/dist/provider/facebook.mjs +0 -150
- package/dist/provider/github.d.mts +0 -140
- package/dist/provider/github.mjs +0 -169
- package/dist/provider/gitlab.d.mts +0 -106
- package/dist/provider/gitlab.mjs +0 -147
- package/dist/provider/google.d.mts +0 -112
- package/dist/provider/google.mjs +0 -109
- package/dist/provider/linkedin.d.mts +0 -132
- package/dist/provider/linkedin.mjs +0 -142
- package/dist/provider/magiclink.d.mts +0 -89
- package/dist/provider/magiclink.mjs +0 -143
- package/dist/provider/microsoft.d.mts +0 -178
- package/dist/provider/microsoft.mjs +0 -177
- package/dist/provider/oauth2.d.mts +0 -176
- package/dist/provider/oauth2.mjs +0 -222
- package/dist/provider/passkey.d.mts +0 -104
- package/dist/provider/passkey.mjs +0 -320
- package/dist/provider/password.d.mts +0 -412
- package/dist/provider/password.mjs +0 -363
- package/dist/provider/provider.d.mts +0 -227
- package/dist/provider/provider.mjs +0 -44
- package/dist/provider/reddit.d.mts +0 -107
- package/dist/provider/reddit.mjs +0 -127
- package/dist/provider/slack.d.mts +0 -114
- package/dist/provider/slack.mjs +0 -138
- package/dist/provider/spotify.d.mts +0 -113
- package/dist/provider/spotify.mjs +0 -135
- package/dist/provider/totp.d.mts +0 -112
- package/dist/provider/totp.mjs +0 -191
- package/dist/provider/twitch.d.mts +0 -108
- package/dist/provider/twitch.mjs +0 -131
- package/dist/provider/vercel.d.mts +0 -177
- package/dist/provider/vercel.mjs +0 -230
- package/dist/random.mjs +0 -86
- package/dist/revocation.d.mts +0 -55
- package/dist/revocation.mjs +0 -63
- package/dist/router/context.d.mts +0 -21
- package/dist/router/context.mjs +0 -193
- package/dist/router/cookies.d.mts +0 -8
- package/dist/router/cookies.mjs +0 -13
- package/dist/router/index.d.mts +0 -21
- package/dist/router/index.mjs +0 -107
- package/dist/router/matcher.d.mts +0 -15
- package/dist/router/matcher.mjs +0 -76
- package/dist/router/middleware/cors.d.mts +0 -15
- package/dist/router/middleware/cors.mjs +0 -114
- package/dist/router/safe-request.d.mts +0 -52
- package/dist/router/safe-request.mjs +0 -160
- package/dist/router/types.d.mts +0 -67
- package/dist/router/types.mjs +0 -1
- package/dist/router/variables.d.mts +0 -12
- package/dist/router/variables.mjs +0 -20
- package/dist/storage/memory.mjs +0 -125
- package/dist/storage/storage.d.mts +0 -179
- package/dist/storage/storage.mjs +0 -104
- package/dist/storage/turso.mjs +0 -117
- package/dist/storage/unstorage.mjs +0 -103
- package/dist/subject.d.mts +0 -62
- package/dist/subject.mjs +0 -36
- package/dist/themes/theme.d.mts +0 -209
- package/dist/themes/theme.mjs +0 -120
- package/dist/toolkit/client.d.mts +0 -169
- package/dist/toolkit/client.mjs +0 -209
- package/dist/toolkit/index.d.mts +0 -9
- package/dist/toolkit/index.mjs +0 -9
- package/dist/toolkit/providers/facebook.d.mts +0 -12
- package/dist/toolkit/providers/facebook.mjs +0 -16
- package/dist/toolkit/providers/github.d.mts +0 -12
- package/dist/toolkit/providers/github.mjs +0 -16
- package/dist/toolkit/providers/google.d.mts +0 -12
- package/dist/toolkit/providers/google.mjs +0 -20
- package/dist/toolkit/providers/strategy.d.mts +0 -40
- package/dist/toolkit/providers/strategy.mjs +0 -1
- package/dist/toolkit/storage.mjs +0 -157
- package/dist/toolkit/utils.mjs +0 -30
- package/dist/types.d.mts +0 -94
- package/dist/types.mjs +0 -1
- package/dist/ui/base.d.mts +0 -30
- package/dist/ui/base.mjs +0 -407
- package/dist/ui/code.d.mts +0 -43
- package/dist/ui/code.mjs +0 -173
- package/dist/ui/form.d.mts +0 -32
- package/dist/ui/form.mjs +0 -49
- package/dist/ui/icon.d.mts +0 -58
- package/dist/ui/icon.mjs +0 -247
- package/dist/ui/magiclink.d.mts +0 -41
- package/dist/ui/magiclink.mjs +0 -152
- package/dist/ui/passkey.d.mts +0 -27
- package/dist/ui/passkey.mjs +0 -323
- package/dist/ui/password.d.mts +0 -42
- package/dist/ui/password.mjs +0 -402
- package/dist/ui/select.d.mts +0 -34
- package/dist/ui/select.mjs +0 -98
- package/dist/ui/totp.d.mts +0 -34
- package/dist/ui/totp.mjs +0 -270
- package/dist/util.mjs +0 -128
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spotify authentication provider for Draft Auth.
|
|
3
|
+
* Implements OAuth 2.0 flow for authenticating users with their Spotify accounts.
|
|
4
|
+
*
|
|
5
|
+
* ## Quick Setup
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { SpotifyProvider } from "@draftlab/auth/provider/spotify"
|
|
9
|
+
*
|
|
10
|
+
* export default issuer({
|
|
11
|
+
* basePath: "/auth", // Important for callback URL
|
|
12
|
+
* providers: {
|
|
13
|
+
* spotify: SpotifyProvider({
|
|
14
|
+
* clientID: process.env.SPOTIFY_CLIENT_ID,
|
|
15
|
+
* clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
|
|
16
|
+
* scopes: ["user-read-private", "user-read-email"]
|
|
17
|
+
* })
|
|
18
|
+
* }
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
|
|
23
|
+
* - Development: `http://localhost:3000/auth/spotify/callback`
|
|
24
|
+
* - Production: `https://yourapp.com/auth/spotify/callback`
|
|
25
|
+
*
|
|
26
|
+
* Register this URL in your Spotify Developer Dashboard.
|
|
27
|
+
*
|
|
28
|
+
* ## Common Scopes
|
|
29
|
+
*
|
|
30
|
+
* - `user-read-private` - Access user's private data
|
|
31
|
+
* - `user-read-email` - Access user's email address
|
|
32
|
+
* - `user-top-read` - Read user's top artists and tracks
|
|
33
|
+
* - `user-read-playback-state` - Read current playback state
|
|
34
|
+
* - `user-modify-playback-state` - Modify playback state
|
|
35
|
+
* - `user-read-currently-playing` - Read currently playing track
|
|
36
|
+
* - `playlist-read-private` - Access private playlists
|
|
37
|
+
* - `playlist-read-public` - Access public playlists
|
|
38
|
+
* - `user-library-read` - Read user's library
|
|
39
|
+
* - `user-follow-read` - Read followed artists and users
|
|
40
|
+
*
|
|
41
|
+
* ## User Data Access
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* success: async (ctx, value) => {
|
|
45
|
+
* if (value.provider === "spotify") {
|
|
46
|
+
* const accessToken = value.tokenset.access
|
|
47
|
+
*
|
|
48
|
+
* // Fetch user profile
|
|
49
|
+
* const userResponse = await fetch('https://api.spotify.com/v1/me', {
|
|
50
|
+
* headers: { Authorization: `Bearer ${accessToken}` }
|
|
51
|
+
* })
|
|
52
|
+
* const user = await userResponse.json()
|
|
53
|
+
*
|
|
54
|
+
* // User info: id, email, display_name, external_urls, images, followers
|
|
55
|
+
* }
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @packageDocumentation
|
|
60
|
+
*/
|
|
61
|
+
import { type Oauth2WrappedConfig } from "./oauth2";
|
|
62
|
+
/**
|
|
63
|
+
* Configuration options for Spotify OAuth 2.0 provider.
|
|
64
|
+
* Extends the base OAuth 2.0 configuration with Spotify-specific documentation.
|
|
65
|
+
*/
|
|
66
|
+
export interface SpotifyConfig extends Oauth2WrappedConfig {
|
|
67
|
+
/**
|
|
68
|
+
* Spotify app client ID.
|
|
69
|
+
* Get this from your Spotify App at https://developer.spotify.com/dashboard
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* {
|
|
74
|
+
* clientID: "abcdef123456"
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
readonly clientID: string;
|
|
79
|
+
/**
|
|
80
|
+
* Spotify app client secret.
|
|
81
|
+
* Keep this secure and never expose it to client-side code.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* {
|
|
86
|
+
* clientSecret: process.env.SPOTIFY_CLIENT_SECRET
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
readonly clientSecret: string;
|
|
91
|
+
/**
|
|
92
|
+
* Spotify OAuth scopes to request access for.
|
|
93
|
+
* Determines what data and actions your app can access.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* {
|
|
98
|
+
* scopes: [
|
|
99
|
+
* "user-read-private", // Access private user data
|
|
100
|
+
* "user-read-email", // Access user email
|
|
101
|
+
* "user-top-read" // Read top artists and tracks
|
|
102
|
+
* ]
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
readonly scopes: string[];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Creates a Spotify OAuth 2.0 authentication provider.
|
|
110
|
+
* Allows users to authenticate using their Spotify accounts.
|
|
111
|
+
*
|
|
112
|
+
* @param config - Spotify OAuth 2.0 configuration
|
|
113
|
+
* @returns OAuth 2.0 provider configured for Spotify
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* // Basic Spotify authentication
|
|
118
|
+
* const basicSpotify = SpotifyProvider({
|
|
119
|
+
* clientID: process.env.SPOTIFY_CLIENT_ID,
|
|
120
|
+
* clientSecret: process.env.SPOTIFY_CLIENT_SECRET
|
|
121
|
+
* })
|
|
122
|
+
*
|
|
123
|
+
* // Spotify with user data access
|
|
124
|
+
* const spotifyWithScopes = SpotifyProvider({
|
|
125
|
+
* clientID: process.env.SPOTIFY_CLIENT_ID,
|
|
126
|
+
* clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
|
|
127
|
+
* scopes: ["user-read-private", "user-read-email", "user-top-read"]
|
|
128
|
+
* })
|
|
129
|
+
*
|
|
130
|
+
* // Using the access token to fetch user data
|
|
131
|
+
* export default issuer({
|
|
132
|
+
* providers: { spotify: spotifyWithScopes },
|
|
133
|
+
* success: async (ctx, value) => {
|
|
134
|
+
* if (value.provider === "spotify") {
|
|
135
|
+
* const token = value.tokenset.access
|
|
136
|
+
*
|
|
137
|
+
* const userRes = await fetch('https://api.spotify.com/v1/me', {
|
|
138
|
+
* headers: { Authorization: `Bearer ${token}` }
|
|
139
|
+
* })
|
|
140
|
+
* const user = await userRes.json()
|
|
141
|
+
*
|
|
142
|
+
* // Optionally fetch top tracks
|
|
143
|
+
* const topRes = await fetch('https://api.spotify.com/v1/me/top/tracks?limit=5', {
|
|
144
|
+
* headers: { Authorization: `Bearer ${token}` }
|
|
145
|
+
* })
|
|
146
|
+
* const { items: topTracks } = await topRes.json()
|
|
147
|
+
*
|
|
148
|
+
* return ctx.subject("user", {
|
|
149
|
+
* spotifyId: user.id,
|
|
150
|
+
* email: user.email,
|
|
151
|
+
* displayName: user.display_name,
|
|
152
|
+
* profileUrl: user.external_urls?.spotify,
|
|
153
|
+
* followers: user.followers?.total,
|
|
154
|
+
* topTracks: topTracks.map(t => t.name)
|
|
155
|
+
* })
|
|
156
|
+
* }
|
|
157
|
+
* }
|
|
158
|
+
* })
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
|
|
162
|
+
* - Development: `http://localhost:3000/auth/spotify/callback`
|
|
163
|
+
* - Production: `https://yourapp.com/auth/spotify/callback`
|
|
164
|
+
*
|
|
165
|
+
* Register this URL in your Spotify Developer Dashboard.
|
|
166
|
+
*/
|
|
167
|
+
export declare const SpotifyProvider: (config: SpotifyConfig) => import("./provider").Provider<import("./oauth2").Oauth2UserData>;
|
|
168
|
+
//# sourceMappingURL=spotify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spotify.d.ts","sourceRoot":"","sources":["../../../src/provider/spotify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,aAAc,SAAQ,mBAAmB;IACzD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAE7B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,aAAa,qEASpD,CAAA"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Twitch authentication provider for Draft Auth.
|
|
3
|
+
* Implements OAuth 2.0 flow for authenticating users with their Twitch accounts.
|
|
4
|
+
*
|
|
5
|
+
* ## Quick Setup
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { TwitchProvider } from "@draftlab/auth/provider/twitch"
|
|
9
|
+
*
|
|
10
|
+
* export default issuer({
|
|
11
|
+
* basePath: "/auth", // Important for callback URL
|
|
12
|
+
* providers: {
|
|
13
|
+
* twitch: TwitchProvider({
|
|
14
|
+
* clientID: process.env.TWITCH_CLIENT_ID,
|
|
15
|
+
* clientSecret: process.env.TWITCH_CLIENT_SECRET,
|
|
16
|
+
* scopes: ["user:read:email"]
|
|
17
|
+
* })
|
|
18
|
+
* }
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
|
|
23
|
+
* - Development: `http://localhost:3000/auth/twitch/callback`
|
|
24
|
+
* - Production: `https://yourapp.com/auth/twitch/callback`
|
|
25
|
+
*
|
|
26
|
+
* Register this URL in your Twitch Developer Console.
|
|
27
|
+
*
|
|
28
|
+
* ## Common Scopes
|
|
29
|
+
*
|
|
30
|
+
* - `user:read:email` - Access user's email address
|
|
31
|
+
* - `user:read:subscriptions` - View user subscriptions
|
|
32
|
+
* - `user:read:follows` - View user's follows
|
|
33
|
+
* - `channel:read:subscriptions` - View channel subscribers
|
|
34
|
+
* - `analytics:read:games` - View game analytics
|
|
35
|
+
* - `bits:read` - View bits information
|
|
36
|
+
*
|
|
37
|
+
* ## User Data Access
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* success: async (ctx, value) => {
|
|
41
|
+
* if (value.provider === "twitch") {
|
|
42
|
+
* const accessToken = value.tokenset.access
|
|
43
|
+
*
|
|
44
|
+
* // Fetch user information
|
|
45
|
+
* const userResponse = await fetch('https://api.twitch.tv/helix/users', {
|
|
46
|
+
* headers: {
|
|
47
|
+
* 'Authorization': `Bearer ${accessToken}`,
|
|
48
|
+
* 'Client-ID': process.env.TWITCH_CLIENT_ID
|
|
49
|
+
* }
|
|
50
|
+
* })
|
|
51
|
+
* const { data } = await userResponse.json()
|
|
52
|
+
* const user = data[0]
|
|
53
|
+
*
|
|
54
|
+
* // User info available: id, login, display_name, email, profile_image_url
|
|
55
|
+
* }
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @packageDocumentation
|
|
60
|
+
*/
|
|
61
|
+
import { type Oauth2WrappedConfig } from "./oauth2";
|
|
62
|
+
/**
|
|
63
|
+
* Configuration options for Twitch OAuth 2.0 provider.
|
|
64
|
+
* Extends the base OAuth 2.0 configuration with Twitch-specific documentation.
|
|
65
|
+
*/
|
|
66
|
+
export interface TwitchConfig extends Oauth2WrappedConfig {
|
|
67
|
+
/**
|
|
68
|
+
* Twitch application client ID.
|
|
69
|
+
* Get this from your Twitch Console at https://dev.twitch.tv/console
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* {
|
|
74
|
+
* clientID: "abcdef123456"
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
readonly clientID: string;
|
|
79
|
+
/**
|
|
80
|
+
* Twitch application client secret.
|
|
81
|
+
* Keep this secure and never expose it to client-side code.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* {
|
|
86
|
+
* clientSecret: process.env.TWITCH_CLIENT_SECRET
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
readonly clientSecret: string;
|
|
91
|
+
/**
|
|
92
|
+
* Twitch OAuth scopes to request access for.
|
|
93
|
+
* Determines what data and actions your app can access.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* {
|
|
98
|
+
* scopes: [
|
|
99
|
+
* "user:read:email", // Access user email
|
|
100
|
+
* "user:read:subscriptions" // View subscriptions
|
|
101
|
+
* ]
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
readonly scopes: string[];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Creates a Twitch OAuth 2.0 authentication provider.
|
|
109
|
+
* Allows users to authenticate using their Twitch accounts.
|
|
110
|
+
*
|
|
111
|
+
* @param config - Twitch OAuth 2.0 configuration
|
|
112
|
+
* @returns OAuth 2.0 provider configured for Twitch
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* // Basic Twitch authentication
|
|
117
|
+
* const basicTwitch = TwitchProvider({
|
|
118
|
+
* clientID: process.env.TWITCH_CLIENT_ID,
|
|
119
|
+
* clientSecret: process.env.TWITCH_CLIENT_SECRET
|
|
120
|
+
* })
|
|
121
|
+
*
|
|
122
|
+
* // Twitch with email scope
|
|
123
|
+
* const twitchWithEmail = TwitchProvider({
|
|
124
|
+
* clientID: process.env.TWITCH_CLIENT_ID,
|
|
125
|
+
* clientSecret: process.env.TWITCH_CLIENT_SECRET,
|
|
126
|
+
* scopes: ["user:read:email"]
|
|
127
|
+
* })
|
|
128
|
+
*
|
|
129
|
+
* // Using the access token to fetch user data
|
|
130
|
+
* export default issuer({
|
|
131
|
+
* providers: { twitch: twitchWithEmail },
|
|
132
|
+
* success: async (ctx, value) => {
|
|
133
|
+
* if (value.provider === "twitch") {
|
|
134
|
+
* const token = value.tokenset.access
|
|
135
|
+
*
|
|
136
|
+
* const userRes = await fetch('https://api.twitch.tv/helix/users', {
|
|
137
|
+
* headers: {
|
|
138
|
+
* 'Authorization': `Bearer ${token}`,
|
|
139
|
+
* 'Client-ID': process.env.TWITCH_CLIENT_ID
|
|
140
|
+
* }
|
|
141
|
+
* })
|
|
142
|
+
* const { data } = await userRes.json()
|
|
143
|
+
* const user = data[0]
|
|
144
|
+
*
|
|
145
|
+
* return ctx.subject("user", {
|
|
146
|
+
* twitchId: user.id,
|
|
147
|
+
* login: user.login,
|
|
148
|
+
* email: user.email,
|
|
149
|
+
* displayName: user.display_name
|
|
150
|
+
* })
|
|
151
|
+
* }
|
|
152
|
+
* }
|
|
153
|
+
* })
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
|
|
157
|
+
* - Development: `http://localhost:3000/auth/twitch/callback`
|
|
158
|
+
* - Production: `https://yourapp.com/auth/twitch/callback`
|
|
159
|
+
*
|
|
160
|
+
* Register this URL in your Twitch Developer Console.
|
|
161
|
+
*/
|
|
162
|
+
export declare const TwitchProvider: (config: TwitchConfig) => import("./provider").Provider<import("./oauth2").Oauth2UserData>;
|
|
163
|
+
//# sourceMappingURL=twitch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twitch.d.ts","sourceRoot":"","sources":["../../../src/provider/twitch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,mBAAmB;IACxD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAE7B;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,YAAY,qEASlD,CAAA"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel OAuth 2.0 + OpenID Connect authentication provider for Draft Auth.
|
|
3
|
+
* Implements "Sign in with Vercel" for user authentication.
|
|
4
|
+
*
|
|
5
|
+
* ## Quick Setup
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { VercelProvider } from "@draftlab/auth/provider/vercel"
|
|
9
|
+
*
|
|
10
|
+
* export default issuer({
|
|
11
|
+
* basePath: "/auth", // Important for callback URL
|
|
12
|
+
* providers: {
|
|
13
|
+
* vercel: VercelProvider({
|
|
14
|
+
* clientID: process.env.VERCEL_CLIENT_ID,
|
|
15
|
+
* clientSecret: process.env.VERCEL_CLIENT_SECRET,
|
|
16
|
+
* scopes: ["openid", "email", "profile"]
|
|
17
|
+
* })
|
|
18
|
+
* }
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
|
|
23
|
+
* - Example: `http://localhost:3000/auth/vercel/callback`
|
|
24
|
+
* - Production: `https://yourapp.com/auth/vercel/callback`
|
|
25
|
+
*
|
|
26
|
+
* ## Creating a Vercel App
|
|
27
|
+
*
|
|
28
|
+
* Before using this provider, create a Vercel App in your dashboard:
|
|
29
|
+
*
|
|
30
|
+
* 1. Go to **Team Settings** → **Apps** → **Create**
|
|
31
|
+
* 2. Fill in app name, description, and logo
|
|
32
|
+
* 3. Add **Authorization Callback URLs**:
|
|
33
|
+
* - Development: `http://localhost:3000/auth/vercel/callback`
|
|
34
|
+
* - Production: `https://yourapp.com/auth/vercel/callback`
|
|
35
|
+
* - Pattern: `{baseURL}{basePath}/{provider}/callback`
|
|
36
|
+
* 4. Configure **Scopes** in the app's Permissions page:
|
|
37
|
+
* - ✅ openid (Required)
|
|
38
|
+
* - ✅ email
|
|
39
|
+
* - ✅ profile
|
|
40
|
+
* - ✅ offline_access (optional, for refresh tokens)
|
|
41
|
+
* 5. Generate a **Client Secret** in the Authentication tab
|
|
42
|
+
* 6. Copy the **Client ID** and **Client Secret**
|
|
43
|
+
*
|
|
44
|
+
* **Important**: You must enable the scopes in the Vercel App dashboard before requesting them!
|
|
45
|
+
*
|
|
46
|
+
* ## Available Scopes
|
|
47
|
+
*
|
|
48
|
+
* - `openid` - **Required**. Enables ID Token issuance for user identification
|
|
49
|
+
* - `email` - Access user's email address in ID Token
|
|
50
|
+
* - `profile` - Access user's name, username, and avatar in ID Token
|
|
51
|
+
* - `offline_access` - Issue a Refresh Token for long-lived access (30 days)
|
|
52
|
+
*
|
|
53
|
+
* ## Tokens Returned
|
|
54
|
+
*
|
|
55
|
+
* - **ID Token**: Signed JWT with user identity claims (verified automatically)
|
|
56
|
+
* - **Access Token**: Bearer token for Vercel API calls (1 hour duration)
|
|
57
|
+
* - **Refresh Token**: Rotates on each use (30 days, requires offline_access scope)
|
|
58
|
+
*
|
|
59
|
+
* ## User Data Access
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* success: async (ctx, value) => {
|
|
63
|
+
* if (value.provider === "vercel") {
|
|
64
|
+
* // ID Token is automatically validated (signature, issuer, audience, expiration)
|
|
65
|
+
* const idToken = value.tokenset.raw.id_token as string | undefined
|
|
66
|
+
* const accessToken = value.tokenset.access
|
|
67
|
+
* const refreshToken = value.tokenset.refresh
|
|
68
|
+
*
|
|
69
|
+
* // Decode ID Token to access user claims
|
|
70
|
+
* if (idToken) {
|
|
71
|
+
* const claims = JSON.parse(
|
|
72
|
+
* Buffer.from(idToken.split('.')[1], 'base64').toString()
|
|
73
|
+
* )
|
|
74
|
+
*
|
|
75
|
+
* // Claims available (depending on scopes):
|
|
76
|
+
* // - sub: Unique Vercel user ID (always present)
|
|
77
|
+
* // - email: User's email (if email scope granted)
|
|
78
|
+
* // - name: User's full name (if profile scope granted)
|
|
79
|
+
* // - picture: Avatar URL (if profile scope granted)
|
|
80
|
+
* // - preferred_username: Vercel username (if profile scope granted)
|
|
81
|
+
*
|
|
82
|
+
* return ctx.subject("user", {
|
|
83
|
+
* email: claims.email || claims.sub
|
|
84
|
+
* })
|
|
85
|
+
* }
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* ## Calling Vercel API
|
|
91
|
+
*
|
|
92
|
+
* Use the access token to call Vercel's REST API:
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* // Get user information
|
|
96
|
+
* const userRes = await fetch('https://api.vercel.com/v2/user', {
|
|
97
|
+
* headers: { Authorization: `Bearer ${accessToken}` }
|
|
98
|
+
* })
|
|
99
|
+
*
|
|
100
|
+
* // Get user's teams
|
|
101
|
+
* const teamsRes = await fetch('https://api.vercel.com/v2/teams', {
|
|
102
|
+
* headers: { Authorization: `Bearer ${accessToken}` }
|
|
103
|
+
* })
|
|
104
|
+
*
|
|
105
|
+
* // Get projects (requires appropriate permissions)
|
|
106
|
+
* const projectsRes = await fetch('https://api.vercel.com/v9/projects', {
|
|
107
|
+
* headers: { Authorization: `Bearer ${accessToken}` }
|
|
108
|
+
* })
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* ## Consent Page
|
|
112
|
+
*
|
|
113
|
+
* The first time a user signs in, Vercel shows a consent page with:
|
|
114
|
+
* - Your app's name and logo
|
|
115
|
+
* - Requested scopes and permissions
|
|
116
|
+
* - Allow/Cancel buttons
|
|
117
|
+
*
|
|
118
|
+
* If the user grants access, they're redirected back with an authorization code.
|
|
119
|
+
* If they cancel, they're redirected with an error parameter.
|
|
120
|
+
*
|
|
121
|
+
* @packageDocumentation
|
|
122
|
+
*/
|
|
123
|
+
import { type Oauth2WrappedConfig } from "./oauth2";
|
|
124
|
+
/**
|
|
125
|
+
* Configuration options for Vercel OAuth 2.0 + OpenID Connect provider.
|
|
126
|
+
* Extends the base OAuth 2.0 configuration with Vercel-specific documentation.
|
|
127
|
+
*/
|
|
128
|
+
export interface VercelConfig extends Oauth2WrappedConfig {
|
|
129
|
+
/**
|
|
130
|
+
* Vercel OAuth App client ID.
|
|
131
|
+
* Found in your Vercel App settings under the Authentication tab.
|
|
132
|
+
*
|
|
133
|
+
* To create an app:
|
|
134
|
+
* 1. Go to Team Settings → Apps → Create
|
|
135
|
+
* 2. Configure app details and callback URLs
|
|
136
|
+
* 3. Copy the Client ID from the Authentication tab
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* {
|
|
141
|
+
* clientID: "oac_abc123xyz789" // Vercel OAuth App Client ID
|
|
142
|
+
* }
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
readonly clientID: string;
|
|
146
|
+
/**
|
|
147
|
+
* Vercel OAuth App client secret.
|
|
148
|
+
* Generated in your Vercel App settings under the Authentication tab.
|
|
149
|
+
* Keep this secure and never expose it to client-side code.
|
|
150
|
+
*
|
|
151
|
+
* To generate:
|
|
152
|
+
* 1. Go to your app's Authentication tab
|
|
153
|
+
* 2. Click "Generate Client Secret"
|
|
154
|
+
* 3. Copy and store securely (shown only once)
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* {
|
|
159
|
+
* clientSecret: process.env.VERCEL_CLIENT_SECRET
|
|
160
|
+
* }
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
readonly clientSecret: string;
|
|
164
|
+
/**
|
|
165
|
+
* OpenID Connect scopes to request.
|
|
166
|
+
* Controls what user information is included in the ID Token.
|
|
167
|
+
*
|
|
168
|
+
* Available scopes (must be enabled in Vercel App dashboard first):
|
|
169
|
+
* - `openid`: Required for ID Token issuance
|
|
170
|
+
* - `email`: User's email address
|
|
171
|
+
* - `profile`: Name, username, and avatar
|
|
172
|
+
* - `offline_access`: Refresh token for long-lived access (optional)
|
|
173
|
+
*
|
|
174
|
+
* **Important**: Enable scopes in: Vercel App → Permissions page
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* {
|
|
179
|
+
* // Basic scopes (usually sufficient)
|
|
180
|
+
* scopes: ["openid", "email", "profile"]
|
|
181
|
+
*
|
|
182
|
+
* // With refresh token support (enable offline_access in dashboard first)
|
|
183
|
+
* scopes: ["openid", "email", "profile", "offline_access"]
|
|
184
|
+
* }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
readonly scopes: string[];
|
|
188
|
+
/**
|
|
189
|
+
* Additional query parameters for Vercel OAuth authorization.
|
|
190
|
+
* Useful for customizing the authorization flow.
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* {
|
|
195
|
+
* query: {
|
|
196
|
+
* prompt: "consent" // Force consent screen every time
|
|
197
|
+
* }
|
|
198
|
+
* }
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
readonly query?: Record<string, string>;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Creates a Vercel OAuth 2.0 + OpenID Connect authentication provider.
|
|
205
|
+
* Implements "Sign in with Vercel" for user authentication.
|
|
206
|
+
*
|
|
207
|
+
* This provider uses the standard OAuth 2.0 Authorization Code Grant flow
|
|
208
|
+
* with PKCE (Proof Key for Code Exchange) for enhanced security.
|
|
209
|
+
*
|
|
210
|
+
* @param config - Vercel OAuth 2.0 configuration
|
|
211
|
+
* @returns OAuth 2.0 provider configured for Vercel
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```ts
|
|
215
|
+
* // Basic Vercel authentication (email + profile)
|
|
216
|
+
* const basicVercel = VercelProvider({
|
|
217
|
+
* clientID: process.env.VERCEL_CLIENT_ID,
|
|
218
|
+
* clientSecret: process.env.VERCEL_CLIENT_SECRET,
|
|
219
|
+
* scopes: ["openid", "email", "profile"]
|
|
220
|
+
* })
|
|
221
|
+
*
|
|
222
|
+
* // Vercel with refresh token support
|
|
223
|
+
* const vercelWithRefresh = VercelProvider({
|
|
224
|
+
* clientID: process.env.VERCEL_CLIENT_ID,
|
|
225
|
+
* clientSecret: process.env.VERCEL_CLIENT_SECRET,
|
|
226
|
+
* scopes: ["openid", "email", "profile", "offline_access"]
|
|
227
|
+
* })
|
|
228
|
+
*
|
|
229
|
+
* // Minimal setup (only user ID in ID Token)
|
|
230
|
+
* const minimalVercel = VercelProvider({
|
|
231
|
+
* clientID: process.env.VERCEL_CLIENT_ID,
|
|
232
|
+
* clientSecret: process.env.VERCEL_CLIENT_SECRET,
|
|
233
|
+
* scopes: ["openid"] // Only sub claim in ID Token
|
|
234
|
+
* })
|
|
235
|
+
*
|
|
236
|
+
* // Using the tokens in your app
|
|
237
|
+
* export default issuer({
|
|
238
|
+
* providers: { vercel: vercelWithRefresh },
|
|
239
|
+
* success: async (ctx, value) => {
|
|
240
|
+
* if (value.provider === "vercel") {
|
|
241
|
+
* const idToken = value.tokenset.raw.id_token as string | undefined
|
|
242
|
+
* const accessToken = value.tokenset.access
|
|
243
|
+
* const refreshToken = value.tokenset.refresh
|
|
244
|
+
*
|
|
245
|
+
* if (idToken) {
|
|
246
|
+
* // Decode ID Token to access user claims
|
|
247
|
+
* // (Already validated by oauth2.ts - signature, issuer, audience, exp)
|
|
248
|
+
* const claims = JSON.parse(
|
|
249
|
+
* Buffer.from(idToken.split('.')[1], 'base64').toString()
|
|
250
|
+
* )
|
|
251
|
+
*
|
|
252
|
+
* // Claims available (depending on scopes):
|
|
253
|
+
* // - sub: Vercel user ID (always present)
|
|
254
|
+
* // - email: user@example.com (if email scope)
|
|
255
|
+
* // - name: "John Doe" (if profile scope)
|
|
256
|
+
* // - picture: "https://..." (if profile scope)
|
|
257
|
+
* // - preferred_username: "johndoe" (if profile scope)
|
|
258
|
+
*
|
|
259
|
+
* // Optionally call Vercel API for more data
|
|
260
|
+
* const userRes = await fetch('https://api.vercel.com/v2/user', {
|
|
261
|
+
* headers: { Authorization: `Bearer ${accessToken}` }
|
|
262
|
+
* })
|
|
263
|
+
* const user = await userRes.json()
|
|
264
|
+
*
|
|
265
|
+
* // Get user's teams
|
|
266
|
+
* const teamsRes = await fetch('https://api.vercel.com/v2/teams', {
|
|
267
|
+
* headers: { Authorization: `Bearer ${accessToken}` }
|
|
268
|
+
* })
|
|
269
|
+
* const teams = await teamsRes.json()
|
|
270
|
+
*
|
|
271
|
+
* return ctx.subject("user", {
|
|
272
|
+
* vercelId: claims.sub,
|
|
273
|
+
* email: claims.email,
|
|
274
|
+
* name: claims.name,
|
|
275
|
+
* username: claims.preferred_username,
|
|
276
|
+
* avatar: claims.picture,
|
|
277
|
+
* teamCount: teams.teams?.length || 0
|
|
278
|
+
* })
|
|
279
|
+
* }
|
|
280
|
+
* }
|
|
281
|
+
* }
|
|
282
|
+
* })
|
|
283
|
+
* ```
|
|
284
|
+
*
|
|
285
|
+
* @remarks
|
|
286
|
+
* - Requires creating a Vercel App in Team Settings → Apps
|
|
287
|
+
* - PKCE is enabled by default for enhanced security
|
|
288
|
+
* - ID Token is automatically validated (signature, issuer, audience, expiration)
|
|
289
|
+
* - Access tokens expire after 1 hour
|
|
290
|
+
* - Refresh tokens rotate on each use and last 30 days
|
|
291
|
+
* - The `openid` scope is required for ID Token issuance
|
|
292
|
+
*/
|
|
293
|
+
export declare const VercelProvider: (config: VercelConfig) => import("./provider").Provider<import("./oauth2").Oauth2UserData>;
|
|
294
|
+
//# sourceMappingURL=vercel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel.d.ts","sourceRoot":"","sources":["../../../src/provider/vercel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyHG;AAEH,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,mBAAmB;IACxD;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAE7B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;IAEzB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,YAAY,qEAYlD,CAAA"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/random.d.ts
|
|
2
1
|
/**
|
|
3
2
|
* Cryptographic utilities for secure random generation and comparison operations.
|
|
4
3
|
* These functions are designed to prevent timing attacks and provide unbiased randomness.
|
|
@@ -19,7 +18,7 @@
|
|
|
19
18
|
* // Returns: "4A7bC9dF2gH5iJ8kL1mN4pQ7rS0tU" (example)
|
|
20
19
|
* ```
|
|
21
20
|
*/
|
|
22
|
-
declare const generateSecureToken: (length?: number) => string;
|
|
21
|
+
export declare const generateSecureToken: (length?: number) => string;
|
|
23
22
|
/**
|
|
24
23
|
* Generates a cryptographically secure string of random digits without modulo bias.
|
|
25
24
|
* Uses rejection sampling to ensure each digit (0-9) has an equal probability of being selected.
|
|
@@ -38,7 +37,7 @@ declare const generateSecureToken: (length?: number) => string;
|
|
|
38
37
|
*
|
|
39
38
|
* @throws {RangeError} If length is not a positive number
|
|
40
39
|
*/
|
|
41
|
-
declare const generateUnbiasedDigits: (length: number) => string;
|
|
40
|
+
export declare const generateUnbiasedDigits: (length: number) => string;
|
|
42
41
|
/**
|
|
43
42
|
* Performs a timing-safe comparison of two strings to prevent timing attacks.
|
|
44
43
|
* Always takes the same amount of time regardless of where the strings differ,
|
|
@@ -61,6 +60,5 @@ declare const generateUnbiasedDigits: (length: number) => string;
|
|
|
61
60
|
* timingSafeCompare("abc", "abcd") // false
|
|
62
61
|
* ```
|
|
63
62
|
*/
|
|
64
|
-
declare const timingSafeCompare: (a: string, b: string) => boolean;
|
|
65
|
-
//#
|
|
66
|
-
export { generateSecureToken, generateUnbiasedDigits, timingSafeCompare };
|
|
63
|
+
export declare const timingSafeCompare: (a: string, b: string) => boolean;
|
|
64
|
+
//# sourceMappingURL=random.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random.d.ts","sourceRoot":"","sources":["../../src/random.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAQ,MAAW,KAAG,MAWzD,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,KAAG,MAevD,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,OAQxD,CAAA"}
|