@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.
Files changed (272) hide show
  1. package/dist/esm/allow.js +26 -0
  2. package/dist/esm/client.js +254 -0
  3. package/dist/esm/core.js +597 -0
  4. package/dist/esm/css.d.js +0 -0
  5. package/dist/esm/error.js +88 -0
  6. package/dist/esm/index.js +5 -0
  7. package/dist/esm/keys.js +126 -0
  8. package/dist/esm/mutex.js +53 -0
  9. package/dist/esm/pkce.js +87 -0
  10. package/dist/esm/provider/apple.js +15 -0
  11. package/dist/esm/provider/code.js +62 -0
  12. package/dist/esm/provider/discord.js +15 -0
  13. package/dist/esm/provider/facebook.js +15 -0
  14. package/dist/esm/provider/github.js +15 -0
  15. package/dist/esm/provider/gitlab.js +15 -0
  16. package/dist/esm/provider/google.js +16 -0
  17. package/dist/esm/provider/linkedin.js +15 -0
  18. package/dist/esm/provider/magiclink.js +83 -0
  19. package/dist/esm/provider/microsoft.js +15 -0
  20. package/dist/esm/provider/oauth2.js +130 -0
  21. package/dist/esm/provider/password.js +331 -0
  22. package/dist/esm/provider/provider.js +18 -0
  23. package/dist/esm/provider/reddit.js +15 -0
  24. package/dist/esm/provider/slack.js +15 -0
  25. package/dist/esm/provider/spotify.js +15 -0
  26. package/dist/esm/provider/twitch.js +15 -0
  27. package/dist/esm/provider/vercel.js +17 -0
  28. package/dist/esm/random.js +40 -0
  29. package/dist/esm/revocation.js +27 -0
  30. package/dist/esm/storage/memory.js +110 -0
  31. package/dist/esm/storage/storage.js +56 -0
  32. package/dist/esm/storage/turso.js +93 -0
  33. package/dist/esm/storage/unstorage.js +78 -0
  34. package/dist/esm/subject.js +7 -0
  35. package/dist/esm/themes/theme.js +115 -0
  36. package/dist/esm/toolkit/client.js +119 -0
  37. package/dist/esm/toolkit/index.js +25 -0
  38. package/dist/esm/toolkit/providers/facebook.js +11 -0
  39. package/dist/esm/toolkit/providers/github.js +11 -0
  40. package/dist/esm/toolkit/providers/google.js +11 -0
  41. package/dist/esm/toolkit/providers/strategy.js +0 -0
  42. package/dist/esm/toolkit/storage.js +81 -0
  43. package/dist/esm/toolkit/utils.js +18 -0
  44. package/dist/esm/types.js +0 -0
  45. package/dist/esm/ui/base.js +478 -0
  46. package/dist/esm/ui/code.js +186 -0
  47. package/dist/esm/ui/form.js +46 -0
  48. package/dist/esm/ui/icon.js +242 -0
  49. package/dist/esm/ui/magiclink.js +158 -0
  50. package/dist/esm/ui/password.js +435 -0
  51. package/dist/esm/ui/select.js +102 -0
  52. package/dist/esm/util.js +59 -0
  53. package/dist/{allow.d.mts → types/allow.d.ts} +9 -11
  54. package/dist/types/allow.d.ts.map +1 -0
  55. package/dist/types/client.d.ts +462 -0
  56. package/dist/types/client.d.ts.map +1 -0
  57. package/dist/types/core.d.ts +113 -0
  58. package/dist/types/core.d.ts.map +1 -0
  59. package/dist/{error.d.mts → types/error.d.ts} +95 -97
  60. package/dist/types/error.d.ts.map +1 -0
  61. package/dist/types/index.d.ts +2 -0
  62. package/dist/types/index.d.ts.map +1 -0
  63. package/dist/{keys.d.mts → types/keys.d.ts} +20 -24
  64. package/dist/types/keys.d.ts.map +1 -0
  65. package/dist/types/mutex.d.ts +42 -0
  66. package/dist/types/mutex.d.ts.map +1 -0
  67. package/dist/{pkce.d.mts → types/pkce.d.ts} +10 -11
  68. package/dist/types/pkce.d.ts.map +1 -0
  69. package/dist/types/provider/apple.d.ts +197 -0
  70. package/dist/types/provider/apple.d.ts.map +1 -0
  71. package/dist/types/provider/code.d.ts +288 -0
  72. package/dist/types/provider/code.d.ts.map +1 -0
  73. package/dist/types/provider/discord.d.ts +206 -0
  74. package/dist/types/provider/discord.d.ts.map +1 -0
  75. package/dist/types/provider/facebook.d.ts +200 -0
  76. package/dist/types/provider/facebook.d.ts.map +1 -0
  77. package/dist/types/provider/github.d.ts +220 -0
  78. package/dist/types/provider/github.d.ts.map +1 -0
  79. package/dist/types/provider/gitlab.d.ts +180 -0
  80. package/dist/types/provider/gitlab.d.ts.map +1 -0
  81. package/dist/types/provider/google.d.ts +158 -0
  82. package/dist/types/provider/google.d.ts.map +1 -0
  83. package/dist/types/provider/linkedin.d.ts +190 -0
  84. package/dist/types/provider/linkedin.d.ts.map +1 -0
  85. package/dist/types/provider/magiclink.d.ts +141 -0
  86. package/dist/types/provider/magiclink.d.ts.map +1 -0
  87. package/dist/types/provider/microsoft.d.ts +247 -0
  88. package/dist/types/provider/microsoft.d.ts.map +1 -0
  89. package/dist/types/provider/oauth2.d.ts +229 -0
  90. package/dist/types/provider/oauth2.d.ts.map +1 -0
  91. package/dist/types/provider/password.d.ts +408 -0
  92. package/dist/types/provider/password.d.ts.map +1 -0
  93. package/dist/types/provider/provider.d.ts +226 -0
  94. package/dist/types/provider/provider.d.ts.map +1 -0
  95. package/dist/types/provider/reddit.d.ts +159 -0
  96. package/dist/types/provider/reddit.d.ts.map +1 -0
  97. package/dist/types/provider/slack.d.ts +171 -0
  98. package/dist/types/provider/slack.d.ts.map +1 -0
  99. package/dist/types/provider/spotify.d.ts +168 -0
  100. package/dist/types/provider/spotify.d.ts.map +1 -0
  101. package/dist/types/provider/twitch.d.ts +163 -0
  102. package/dist/types/provider/twitch.d.ts.map +1 -0
  103. package/dist/types/provider/vercel.d.ts +294 -0
  104. package/dist/types/provider/vercel.d.ts.map +1 -0
  105. package/dist/{random.d.mts → types/random.d.ts} +4 -6
  106. package/dist/types/random.d.ts.map +1 -0
  107. package/dist/types/revocation.d.ts +76 -0
  108. package/dist/types/revocation.d.ts.map +1 -0
  109. package/dist/{storage/memory.d.mts → types/storage/memory.d.ts} +17 -21
  110. package/dist/types/storage/memory.d.ts.map +1 -0
  111. package/dist/types/storage/storage.d.ts +177 -0
  112. package/dist/types/storage/storage.d.ts.map +1 -0
  113. package/dist/{storage/turso.d.mts → types/storage/turso.d.ts} +4 -8
  114. package/dist/types/storage/turso.d.ts.map +1 -0
  115. package/dist/{storage/unstorage.d.mts → types/storage/unstorage.d.ts} +12 -11
  116. package/dist/types/storage/unstorage.d.ts.map +1 -0
  117. package/dist/types/subject.d.ts +115 -0
  118. package/dist/types/subject.d.ts.map +1 -0
  119. package/dist/types/themes/theme.d.ts +207 -0
  120. package/dist/types/themes/theme.d.ts.map +1 -0
  121. package/dist/types/toolkit/client.d.ts +235 -0
  122. package/dist/types/toolkit/client.d.ts.map +1 -0
  123. package/dist/types/toolkit/index.d.ts +45 -0
  124. package/dist/types/toolkit/index.d.ts.map +1 -0
  125. package/dist/types/toolkit/providers/facebook.d.ts +8 -0
  126. package/dist/types/toolkit/providers/facebook.d.ts.map +1 -0
  127. package/dist/types/toolkit/providers/github.d.ts +8 -0
  128. package/dist/types/toolkit/providers/github.d.ts.map +1 -0
  129. package/dist/types/toolkit/providers/google.d.ts +8 -0
  130. package/dist/types/toolkit/providers/google.d.ts.map +1 -0
  131. package/dist/types/toolkit/providers/strategy.d.ts +38 -0
  132. package/dist/types/toolkit/providers/strategy.d.ts.map +1 -0
  133. package/dist/{toolkit/storage.d.mts → types/toolkit/storage.d.ts} +37 -39
  134. package/dist/types/toolkit/storage.d.ts.map +1 -0
  135. package/dist/{toolkit/utils.d.mts → types/toolkit/utils.d.ts} +2 -4
  136. package/dist/types/toolkit/utils.d.ts.map +1 -0
  137. package/dist/types/types.d.ts +92 -0
  138. package/dist/types/types.d.ts.map +1 -0
  139. package/dist/types/ui/base.d.ts +18 -0
  140. package/dist/types/ui/base.d.ts.map +1 -0
  141. package/dist/types/ui/code.d.ts +43 -0
  142. package/dist/types/ui/code.d.ts.map +1 -0
  143. package/dist/types/ui/form.d.ts +24 -0
  144. package/dist/types/ui/form.d.ts.map +1 -0
  145. package/dist/types/ui/icon.d.ts +60 -0
  146. package/dist/types/ui/icon.d.ts.map +1 -0
  147. package/dist/types/ui/magiclink.d.ts +41 -0
  148. package/dist/types/ui/magiclink.d.ts.map +1 -0
  149. package/dist/types/ui/password.d.ts +43 -0
  150. package/dist/types/ui/password.d.ts.map +1 -0
  151. package/dist/types/ui/select.d.ts +33 -0
  152. package/dist/types/ui/select.d.ts.map +1 -0
  153. package/dist/{util.d.mts → types/util.d.ts} +11 -13
  154. package/dist/types/util.d.ts.map +1 -0
  155. package/package.json +10 -16
  156. package/dist/adapters/node.d.mts +0 -18
  157. package/dist/adapters/node.mjs +0 -69
  158. package/dist/allow.mjs +0 -63
  159. package/dist/client.d.mts +0 -456
  160. package/dist/client.mjs +0 -283
  161. package/dist/core.d.mts +0 -110
  162. package/dist/core.mjs +0 -595
  163. package/dist/error.mjs +0 -237
  164. package/dist/index.d.mts +0 -2
  165. package/dist/index.mjs +0 -3
  166. package/dist/keys.mjs +0 -146
  167. package/dist/mutex.d.mts +0 -44
  168. package/dist/mutex.mjs +0 -110
  169. package/dist/pkce.mjs +0 -157
  170. package/dist/provider/apple.d.mts +0 -111
  171. package/dist/provider/apple.mjs +0 -164
  172. package/dist/provider/code.d.mts +0 -228
  173. package/dist/provider/code.mjs +0 -246
  174. package/dist/provider/discord.d.mts +0 -146
  175. package/dist/provider/discord.mjs +0 -156
  176. package/dist/provider/facebook.d.mts +0 -142
  177. package/dist/provider/facebook.mjs +0 -150
  178. package/dist/provider/github.d.mts +0 -140
  179. package/dist/provider/github.mjs +0 -169
  180. package/dist/provider/gitlab.d.mts +0 -106
  181. package/dist/provider/gitlab.mjs +0 -147
  182. package/dist/provider/google.d.mts +0 -112
  183. package/dist/provider/google.mjs +0 -109
  184. package/dist/provider/linkedin.d.mts +0 -132
  185. package/dist/provider/linkedin.mjs +0 -142
  186. package/dist/provider/magiclink.d.mts +0 -89
  187. package/dist/provider/magiclink.mjs +0 -143
  188. package/dist/provider/microsoft.d.mts +0 -178
  189. package/dist/provider/microsoft.mjs +0 -177
  190. package/dist/provider/oauth2.d.mts +0 -176
  191. package/dist/provider/oauth2.mjs +0 -222
  192. package/dist/provider/passkey.d.mts +0 -104
  193. package/dist/provider/passkey.mjs +0 -320
  194. package/dist/provider/password.d.mts +0 -412
  195. package/dist/provider/password.mjs +0 -363
  196. package/dist/provider/provider.d.mts +0 -227
  197. package/dist/provider/provider.mjs +0 -44
  198. package/dist/provider/reddit.d.mts +0 -107
  199. package/dist/provider/reddit.mjs +0 -127
  200. package/dist/provider/slack.d.mts +0 -114
  201. package/dist/provider/slack.mjs +0 -138
  202. package/dist/provider/spotify.d.mts +0 -113
  203. package/dist/provider/spotify.mjs +0 -135
  204. package/dist/provider/totp.d.mts +0 -112
  205. package/dist/provider/totp.mjs +0 -191
  206. package/dist/provider/twitch.d.mts +0 -108
  207. package/dist/provider/twitch.mjs +0 -131
  208. package/dist/provider/vercel.d.mts +0 -177
  209. package/dist/provider/vercel.mjs +0 -230
  210. package/dist/random.mjs +0 -86
  211. package/dist/revocation.d.mts +0 -55
  212. package/dist/revocation.mjs +0 -63
  213. package/dist/router/context.d.mts +0 -21
  214. package/dist/router/context.mjs +0 -193
  215. package/dist/router/cookies.d.mts +0 -8
  216. package/dist/router/cookies.mjs +0 -13
  217. package/dist/router/index.d.mts +0 -21
  218. package/dist/router/index.mjs +0 -107
  219. package/dist/router/matcher.d.mts +0 -15
  220. package/dist/router/matcher.mjs +0 -76
  221. package/dist/router/middleware/cors.d.mts +0 -15
  222. package/dist/router/middleware/cors.mjs +0 -114
  223. package/dist/router/safe-request.d.mts +0 -52
  224. package/dist/router/safe-request.mjs +0 -160
  225. package/dist/router/types.d.mts +0 -67
  226. package/dist/router/types.mjs +0 -1
  227. package/dist/router/variables.d.mts +0 -12
  228. package/dist/router/variables.mjs +0 -20
  229. package/dist/storage/memory.mjs +0 -125
  230. package/dist/storage/storage.d.mts +0 -179
  231. package/dist/storage/storage.mjs +0 -104
  232. package/dist/storage/turso.mjs +0 -117
  233. package/dist/storage/unstorage.mjs +0 -103
  234. package/dist/subject.d.mts +0 -62
  235. package/dist/subject.mjs +0 -36
  236. package/dist/themes/theme.d.mts +0 -209
  237. package/dist/themes/theme.mjs +0 -120
  238. package/dist/toolkit/client.d.mts +0 -169
  239. package/dist/toolkit/client.mjs +0 -209
  240. package/dist/toolkit/index.d.mts +0 -9
  241. package/dist/toolkit/index.mjs +0 -9
  242. package/dist/toolkit/providers/facebook.d.mts +0 -12
  243. package/dist/toolkit/providers/facebook.mjs +0 -16
  244. package/dist/toolkit/providers/github.d.mts +0 -12
  245. package/dist/toolkit/providers/github.mjs +0 -16
  246. package/dist/toolkit/providers/google.d.mts +0 -12
  247. package/dist/toolkit/providers/google.mjs +0 -20
  248. package/dist/toolkit/providers/strategy.d.mts +0 -40
  249. package/dist/toolkit/providers/strategy.mjs +0 -1
  250. package/dist/toolkit/storage.mjs +0 -157
  251. package/dist/toolkit/utils.mjs +0 -30
  252. package/dist/types.d.mts +0 -94
  253. package/dist/types.mjs +0 -1
  254. package/dist/ui/base.d.mts +0 -30
  255. package/dist/ui/base.mjs +0 -407
  256. package/dist/ui/code.d.mts +0 -43
  257. package/dist/ui/code.mjs +0 -173
  258. package/dist/ui/form.d.mts +0 -32
  259. package/dist/ui/form.mjs +0 -49
  260. package/dist/ui/icon.d.mts +0 -58
  261. package/dist/ui/icon.mjs +0 -247
  262. package/dist/ui/magiclink.d.mts +0 -41
  263. package/dist/ui/magiclink.mjs +0 -152
  264. package/dist/ui/passkey.d.mts +0 -27
  265. package/dist/ui/passkey.mjs +0 -323
  266. package/dist/ui/password.d.mts +0 -42
  267. package/dist/ui/password.mjs +0 -402
  268. package/dist/ui/select.d.mts +0 -34
  269. package/dist/ui/select.mjs +0 -98
  270. package/dist/ui/totp.d.mts +0 -34
  271. package/dist/ui/totp.mjs +0 -270
  272. package/dist/util.mjs +0 -128
@@ -1,135 +0,0 @@
1
- import { Oauth2Provider } from "./oauth2.mjs";
2
-
3
- //#region src/provider/spotify.ts
4
- /**
5
- * Spotify authentication provider for Draft Auth.
6
- * Implements OAuth 2.0 flow for authenticating users with their Spotify accounts.
7
- *
8
- * ## Quick Setup
9
- *
10
- * ```ts
11
- * import { SpotifyProvider } from "@draftlab/auth/provider/spotify"
12
- *
13
- * export default issuer({
14
- * basePath: "/auth", // Important for callback URL
15
- * providers: {
16
- * spotify: SpotifyProvider({
17
- * clientID: process.env.SPOTIFY_CLIENT_ID,
18
- * clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
19
- * scopes: ["user-read-private", "user-read-email"]
20
- * })
21
- * }
22
- * })
23
- * ```
24
- *
25
- * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
26
- * - Development: `http://localhost:3000/auth/spotify/callback`
27
- * - Production: `https://yourapp.com/auth/spotify/callback`
28
- *
29
- * Register this URL in your Spotify Developer Dashboard.
30
- *
31
- * ## Common Scopes
32
- *
33
- * - `user-read-private` - Access user's private data
34
- * - `user-read-email` - Access user's email address
35
- * - `user-top-read` - Read user's top artists and tracks
36
- * - `user-read-playback-state` - Read current playback state
37
- * - `user-modify-playback-state` - Modify playback state
38
- * - `user-read-currently-playing` - Read currently playing track
39
- * - `playlist-read-private` - Access private playlists
40
- * - `playlist-read-public` - Access public playlists
41
- * - `user-library-read` - Read user's library
42
- * - `user-follow-read` - Read followed artists and users
43
- *
44
- * ## User Data Access
45
- *
46
- * ```ts
47
- * success: async (ctx, value) => {
48
- * if (value.provider === "spotify") {
49
- * const accessToken = value.tokenset.access
50
- *
51
- * // Fetch user profile
52
- * const userResponse = await fetch('https://api.spotify.com/v1/me', {
53
- * headers: { Authorization: `Bearer ${accessToken}` }
54
- * })
55
- * const user = await userResponse.json()
56
- *
57
- * // User info: id, email, display_name, external_urls, images, followers
58
- * }
59
- * }
60
- * ```
61
- *
62
- * @packageDocumentation
63
- */
64
- /**
65
- * Creates a Spotify OAuth 2.0 authentication provider.
66
- * Allows users to authenticate using their Spotify accounts.
67
- *
68
- * @param config - Spotify OAuth 2.0 configuration
69
- * @returns OAuth 2.0 provider configured for Spotify
70
- *
71
- * @example
72
- * ```ts
73
- * // Basic Spotify authentication
74
- * const basicSpotify = SpotifyProvider({
75
- * clientID: process.env.SPOTIFY_CLIENT_ID,
76
- * clientSecret: process.env.SPOTIFY_CLIENT_SECRET
77
- * })
78
- *
79
- * // Spotify with user data access
80
- * const spotifyWithScopes = SpotifyProvider({
81
- * clientID: process.env.SPOTIFY_CLIENT_ID,
82
- * clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
83
- * scopes: ["user-read-private", "user-read-email", "user-top-read"]
84
- * })
85
- *
86
- * // Using the access token to fetch user data
87
- * export default issuer({
88
- * providers: { spotify: spotifyWithScopes },
89
- * success: async (ctx, value) => {
90
- * if (value.provider === "spotify") {
91
- * const token = value.tokenset.access
92
- *
93
- * const userRes = await fetch('https://api.spotify.com/v1/me', {
94
- * headers: { Authorization: `Bearer ${token}` }
95
- * })
96
- * const user = await userRes.json()
97
- *
98
- * // Optionally fetch top tracks
99
- * const topRes = await fetch('https://api.spotify.com/v1/me/top/tracks?limit=5', {
100
- * headers: { Authorization: `Bearer ${token}` }
101
- * })
102
- * const { items: topTracks } = await topRes.json()
103
- *
104
- * return ctx.subject("user", {
105
- * spotifyId: user.id,
106
- * email: user.email,
107
- * displayName: user.display_name,
108
- * profileUrl: user.external_urls?.spotify,
109
- * followers: user.followers?.total,
110
- * topTracks: topTracks.map(t => t.name)
111
- * })
112
- * }
113
- * }
114
- * })
115
- * ```
116
- *
117
- * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
118
- * - Development: `http://localhost:3000/auth/spotify/callback`
119
- * - Production: `https://yourapp.com/auth/spotify/callback`
120
- *
121
- * Register this URL in your Spotify Developer Dashboard.
122
- */
123
- const SpotifyProvider = (config) => {
124
- return Oauth2Provider({
125
- ...config,
126
- type: "spotify",
127
- endpoint: {
128
- authorization: "https://accounts.spotify.com/authorize",
129
- token: "https://accounts.spotify.com/api/token"
130
- }
131
- });
132
- };
133
-
134
- //#endregion
135
- export { SpotifyProvider };
@@ -1,112 +0,0 @@
1
- import { Provider } from "./provider.mjs";
2
-
3
- //#region src/provider/totp.d.ts
4
-
5
- /**
6
- * TOTP data model stored in the database.
7
- * Contains the user's TOTP configuration and backup codes.
8
- */
9
- interface TOTPModel {
10
- /** Base32-encoded secret key */
11
- secret: string;
12
- /** Whether TOTP is enabled for this user */
13
- enabled: boolean;
14
- /** Array of one-time backup/recovery codes */
15
- backupCodes: string[];
16
- /** Timestamp when TOTP was first set up */
17
- createdAt: string;
18
- /** Optional user label for the TOTP */
19
- label?: string;
20
- }
21
- /**
22
- * Configuration for the TOTPProvider.
23
- * Defines how the TOTP authentication flow should behave.
24
- */
25
- interface TOTPProviderConfig {
26
- /**
27
- * The human-readable name of the issuer (your application).
28
- * This appears in authenticator apps next to the TOTP entry.
29
- */
30
- issuer: string;
31
- /**
32
- * Custom authorize handler that generates the UI for TOTP login.
33
- * Called when user wants to login with TOTP (main page).
34
- *
35
- * @param req - The HTTP request object
36
- * @param error - Optional error message to display
37
- */
38
- authorize: (req: Request, error?: string) => Promise<Response>;
39
- /**
40
- * Custom register handler that generates the UI for TOTP setup.
41
- * Called when user is setting up TOTP for the first time.
42
- *
43
- * @param req - The HTTP request object
44
- * @param qrCodeUrl - The otpauth:// URL for QR code generation
45
- * @param secret - The raw secret (for manual entry)
46
- * @param backupCodes - Array of backup/recovery codes
47
- * @param error - Optional error message to display
48
- */
49
- register: (req: Request, qrCodeUrl: string, secret: string, backupCodes: string[], error?: string, email?: string) => Promise<Response>;
50
- /**
51
- * Custom recovery handler that generates the UI for backup code entry.
52
- * Called when user wants to use a recovery code instead of TOTP.
53
- *
54
- * @param req - The HTTP request object
55
- * @param error - Optional error message to display
56
- */
57
- recovery: (req: Request, error?: string) => Promise<Response>;
58
- /**
59
- * Optional TOTP algorithm. Defaults to SHA1 for maximum compatibility.
60
- * Most authenticator apps support SHA1, fewer support SHA256/SHA512.
61
- */
62
- algorithm?: "SHA1" | "SHA256" | "SHA512";
63
- /**
64
- * Optional number of digits in TOTP codes. Defaults to 6.
65
- * Some apps support 8 digits for increased security.
66
- */
67
- digits?: 6 | 8;
68
- /**
69
- * Optional validity period for TOTP codes in seconds. Defaults to 30.
70
- * Standard is 30 seconds, some high-security apps use 60.
71
- */
72
- period?: number;
73
- /**
74
- * Optional time window tolerance for clock drift. Defaults to 1.
75
- * Allows tokens from previous/next time window to be valid.
76
- */
77
- window?: number;
78
- /**
79
- * Optional number of backup codes to generate. Defaults to 10.
80
- */
81
- backupCodesCount?: number;
82
- /**
83
- * Optional function to check if a user is allowed to set up TOTP.
84
- */
85
- userCanSetupTOTP?: (userId: string, req: Request) => Promise<boolean>;
86
- /**
87
- * Optional custom label generator for TOTP entries.
88
- * Defaults to using the userId as the label.
89
- */
90
- generateLabel?: (userId: string) => Promise<string>;
91
- }
92
- /**
93
- * Creates a TOTP (Time-based One-Time Password) authentication provider.
94
- *
95
- * TOTP tokens. Users can set up TOTP using any compatible authenticator app
96
- * and use backup codes when their primary device is unavailable.
97
- *
98
- * It handles:
99
- * - TOTP secret generation and QR code creation
100
- * - Token verification with timing attack protection
101
- * - Backup code generation and one-time usage validation
102
- * - Complete setup, verification, and recovery flows
103
- *
104
- * @param config Configuration options for the TOTP provider
105
- * @returns A Provider instance configured for TOTP authentication
106
- */
107
- declare const TOTPProvider: (config: TOTPProviderConfig) => Provider<{
108
- email: string;
109
- method: "totp" | "recovery";
110
- }>;
111
- //#endregion
112
- export { TOTPModel, TOTPProvider, TOTPProviderConfig };
@@ -1,191 +0,0 @@
1
- import { generateSecureToken } from "../random.mjs";
2
- import { Storage } from "../storage/storage.mjs";
3
- import { Secret, TOTP } from "otpauth";
4
-
5
- //#region src/provider/totp.ts
6
- /**
7
- * Configures a provider that supports TOTP (Time-based One-Time Password) authentication.
8
- *
9
- * ```ts
10
- * import { TOTPProvider } from "@draftlab/auth/provider/totp"
11
- *
12
- * export default issuer({
13
- * providers: {
14
- * totp: TOTPProvider({
15
- * issuer: "My Application",
16
- * setup: async (req, qrCode, secret, backupCodes) => {
17
- * return new Response(renderSetupPage(qrCode, secret, backupCodes))
18
- * },
19
- * verify: async (req, error) => {
20
- * return new Response(renderVerifyPage(error))
21
- * },
22
- * recovery: async (req, error) => {
23
- * return new Response(renderRecoveryPage(error))
24
- * }
25
- * })
26
- * },
27
- * // ...
28
- * })
29
- * ```
30
- *
31
- * TOTPProvider implements Time-based One-Time Password authentication.
32
- * It provides secure TOTP token generation and verification with backup recovery codes.
33
- *
34
- * The provider requires configuration of:
35
- * - Issuer name for authenticator apps
36
- * - UI handlers for setup, verification, and recovery flows
37
- * - Optional TOTP parameters (algorithm, digits, period)
38
- *
39
- * It automatically manages:
40
- * - Secure secret generation
41
- * - QR code URL generation for authenticator apps
42
- * - Token validation with timing attack protection
43
- * - Recovery codes generation and one-time usage
44
- * - Storage of TOTP configuration and backup codes
45
- *
46
- * @packageDocumentation
47
- */
48
- const totpKey = (userId) => [
49
- "totp",
50
- "user",
51
- userId
52
- ];
53
- const DEFAULT_CONFIG = {
54
- algorithm: "SHA1",
55
- digits: 6,
56
- period: 30,
57
- window: 1,
58
- backupCodesCount: 4,
59
- qrSize: 200
60
- };
61
- /**
62
- * Creates a TOTP (Time-based One-Time Password) authentication provider.
63
- *
64
- * TOTP tokens. Users can set up TOTP using any compatible authenticator app
65
- * and use backup codes when their primary device is unavailable.
66
- *
67
- * It handles:
68
- * - TOTP secret generation and QR code creation
69
- * - Token verification with timing attack protection
70
- * - Backup code generation and one-time usage validation
71
- * - Complete setup, verification, and recovery flows
72
- *
73
- * @param config Configuration options for the TOTP provider
74
- * @returns A Provider instance configured for TOTP authentication
75
- */
76
- const TOTPProvider = (config) => {
77
- const { issuer, algorithm = DEFAULT_CONFIG.algorithm, digits = DEFAULT_CONFIG.digits, period = DEFAULT_CONFIG.period, window = DEFAULT_CONFIG.window, backupCodesCount = DEFAULT_CONFIG.backupCodesCount } = config;
78
- return {
79
- type: "totp",
80
- init(routes, ctx) {
81
- const getTOTPData = async (userId) => {
82
- return await Storage.get(ctx.storage, totpKey(userId));
83
- };
84
- const saveTOTPData = async (userId, data) => {
85
- await Storage.set(ctx.storage, totpKey(userId), data);
86
- };
87
- const generateBackupCodes = (count) => {
88
- const codes = [];
89
- for (let i = 0; i < count; i++) {
90
- const code = generateSecureToken().slice(0, 8).toUpperCase();
91
- codes.push(`${code.slice(0, 4)}-${code.slice(4)}`);
92
- }
93
- return codes;
94
- };
95
- const createTOTPInstance = (secret, label) => {
96
- return new TOTP({
97
- issuer,
98
- label,
99
- algorithm,
100
- digits,
101
- period,
102
- secret
103
- });
104
- };
105
- routes.get("/register", async (c) => {
106
- return ctx.forward(c, await config.register(c.request, "", "", []));
107
- });
108
- routes.post("/register", async (c) => {
109
- const formData = await c.formData();
110
- const email = formData.get("email")?.toString();
111
- const action = formData.get("action")?.toString();
112
- if (!email) return ctx.forward(c, await config.register(c.request, "", "", [], "Email is required"));
113
- if (action === "generate") {
114
- const secret = new Secret({ size: 20 });
115
- const label = config.generateLabel ? await config.generateLabel(email) : email;
116
- const backupCodes = generateBackupCodes(backupCodesCount);
117
- const qrCodeUrl$1 = createTOTPInstance(secret.base32, label).toString();
118
- await saveTOTPData(email, {
119
- secret: secret.base32,
120
- enabled: false,
121
- backupCodes,
122
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
123
- label
124
- });
125
- return ctx.forward(c, await config.register(c.request, qrCodeUrl$1, secret.base32, backupCodes, void 0, email));
126
- }
127
- const token = formData.get("token")?.toString();
128
- if (!token) return ctx.forward(c, await config.register(c.request, "", "", [], "Verification code is required"));
129
- const totpData = await getTOTPData(email);
130
- if (!totpData) return ctx.forward(c, await config.register(c.request, "", "", [], "TOTP setup session not found"));
131
- const totp = createTOTPInstance(totpData.secret, totpData.label || email);
132
- if (totp.validate({
133
- token,
134
- window
135
- }) !== null) {
136
- totpData.enabled = true;
137
- await saveTOTPData(email, totpData);
138
- return ctx.success(c, {
139
- email,
140
- method: "totp"
141
- });
142
- }
143
- const qrCodeUrl = totp.toString();
144
- return ctx.forward(c, await config.register(c.request, qrCodeUrl, totpData.secret, totpData.backupCodes, "Invalid verification code. Please try again."));
145
- });
146
- routes.get("/authorize", async (c) => {
147
- return ctx.forward(c, await config.authorize(c.request));
148
- });
149
- routes.post("/authorize", async (c) => {
150
- const formData = await c.formData();
151
- const email = formData.get("email")?.toString();
152
- const token = formData.get("token")?.toString();
153
- if (!email || !token) return ctx.forward(c, await config.authorize(c.request, "Email and verification code are required"));
154
- const totpData = await getTOTPData(email);
155
- if (!totpData || !totpData.enabled) return ctx.forward(c, await config.authorize(c.request, "TOTP is not set up for this email"));
156
- if (createTOTPInstance(totpData.secret, totpData.label || email).validate({
157
- token,
158
- window
159
- }) !== null) return ctx.success(c, {
160
- email,
161
- method: "totp"
162
- });
163
- return ctx.forward(c, await config.authorize(c.request, "Invalid verification code"));
164
- });
165
- routes.get("/recovery", async (c) => {
166
- return ctx.forward(c, await config.recovery(c.request));
167
- });
168
- routes.post("/recovery", async (c) => {
169
- const formData = await c.formData();
170
- const email = formData.get("email")?.toString();
171
- const code = formData.get("code")?.toString()?.toUpperCase();
172
- if (!email || !code) return ctx.forward(c, await config.recovery(c.request, "Email and recovery code are required"));
173
- const totpData = await getTOTPData(email);
174
- if (!totpData || !totpData.enabled) return ctx.forward(c, await config.recovery(c.request, "TOTP is not set up for this email"));
175
- const codeIndex = totpData.backupCodes.indexOf(code);
176
- if (codeIndex !== -1) {
177
- totpData.backupCodes.splice(codeIndex, 1);
178
- await saveTOTPData(email, totpData);
179
- return ctx.success(c, {
180
- email,
181
- method: "recovery"
182
- });
183
- }
184
- return ctx.forward(c, await config.recovery(c.request, "Invalid or already used recovery code"));
185
- });
186
- }
187
- };
188
- };
189
-
190
- //#endregion
191
- export { TOTPProvider };
@@ -1,108 +0,0 @@
1
- import { Provider } from "./provider.mjs";
2
- import { Oauth2UserData, Oauth2WrappedConfig } from "./oauth2.mjs";
3
-
4
- //#region src/provider/twitch.d.ts
5
-
6
- /**
7
- * Configuration options for Twitch OAuth 2.0 provider.
8
- * Extends the base OAuth 2.0 configuration with Twitch-specific documentation.
9
- */
10
- interface TwitchConfig extends Oauth2WrappedConfig {
11
- /**
12
- * Twitch application client ID.
13
- * Get this from your Twitch Console at https://dev.twitch.tv/console
14
- *
15
- * @example
16
- * ```ts
17
- * {
18
- * clientID: "abcdef123456"
19
- * }
20
- * ```
21
- */
22
- readonly clientID: string;
23
- /**
24
- * Twitch application client secret.
25
- * Keep this secure and never expose it to client-side code.
26
- *
27
- * @example
28
- * ```ts
29
- * {
30
- * clientSecret: process.env.TWITCH_CLIENT_SECRET
31
- * }
32
- * ```
33
- */
34
- readonly clientSecret: string;
35
- /**
36
- * Twitch OAuth scopes to request access for.
37
- * Determines what data and actions your app can access.
38
- *
39
- * @example
40
- * ```ts
41
- * {
42
- * scopes: [
43
- * "user:read:email", // Access user email
44
- * "user:read:subscriptions" // View subscriptions
45
- * ]
46
- * }
47
- * ```
48
- */
49
- readonly scopes: string[];
50
- }
51
- /**
52
- * Creates a Twitch OAuth 2.0 authentication provider.
53
- * Allows users to authenticate using their Twitch accounts.
54
- *
55
- * @param config - Twitch OAuth 2.0 configuration
56
- * @returns OAuth 2.0 provider configured for Twitch
57
- *
58
- * @example
59
- * ```ts
60
- * // Basic Twitch authentication
61
- * const basicTwitch = TwitchProvider({
62
- * clientID: process.env.TWITCH_CLIENT_ID,
63
- * clientSecret: process.env.TWITCH_CLIENT_SECRET
64
- * })
65
- *
66
- * // Twitch with email scope
67
- * const twitchWithEmail = TwitchProvider({
68
- * clientID: process.env.TWITCH_CLIENT_ID,
69
- * clientSecret: process.env.TWITCH_CLIENT_SECRET,
70
- * scopes: ["user:read:email"]
71
- * })
72
- *
73
- * // Using the access token to fetch user data
74
- * export default issuer({
75
- * providers: { twitch: twitchWithEmail },
76
- * success: async (ctx, value) => {
77
- * if (value.provider === "twitch") {
78
- * const token = value.tokenset.access
79
- *
80
- * const userRes = await fetch('https://api.twitch.tv/helix/users', {
81
- * headers: {
82
- * 'Authorization': `Bearer ${token}`,
83
- * 'Client-ID': process.env.TWITCH_CLIENT_ID
84
- * }
85
- * })
86
- * const { data } = await userRes.json()
87
- * const user = data[0]
88
- *
89
- * return ctx.subject("user", {
90
- * twitchId: user.id,
91
- * login: user.login,
92
- * email: user.email,
93
- * displayName: user.display_name
94
- * })
95
- * }
96
- * }
97
- * })
98
- * ```
99
- *
100
- * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
101
- * - Development: `http://localhost:3000/auth/twitch/callback`
102
- * - Production: `https://yourapp.com/auth/twitch/callback`
103
- *
104
- * Register this URL in your Twitch Developer Console.
105
- */
106
- declare const TwitchProvider: (config: TwitchConfig) => Provider<Oauth2UserData>;
107
- //#endregion
108
- export { TwitchConfig, TwitchProvider };
@@ -1,131 +0,0 @@
1
- import { Oauth2Provider } from "./oauth2.mjs";
2
-
3
- //#region src/provider/twitch.ts
4
- /**
5
- * Twitch authentication provider for Draft Auth.
6
- * Implements OAuth 2.0 flow for authenticating users with their Twitch accounts.
7
- *
8
- * ## Quick Setup
9
- *
10
- * ```ts
11
- * import { TwitchProvider } from "@draftlab/auth/provider/twitch"
12
- *
13
- * export default issuer({
14
- * basePath: "/auth", // Important for callback URL
15
- * providers: {
16
- * twitch: TwitchProvider({
17
- * clientID: process.env.TWITCH_CLIENT_ID,
18
- * clientSecret: process.env.TWITCH_CLIENT_SECRET,
19
- * scopes: ["user:read:email"]
20
- * })
21
- * }
22
- * })
23
- * ```
24
- *
25
- * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
26
- * - Development: `http://localhost:3000/auth/twitch/callback`
27
- * - Production: `https://yourapp.com/auth/twitch/callback`
28
- *
29
- * Register this URL in your Twitch Developer Console.
30
- *
31
- * ## Common Scopes
32
- *
33
- * - `user:read:email` - Access user's email address
34
- * - `user:read:subscriptions` - View user subscriptions
35
- * - `user:read:follows` - View user's follows
36
- * - `channel:read:subscriptions` - View channel subscribers
37
- * - `analytics:read:games` - View game analytics
38
- * - `bits:read` - View bits information
39
- *
40
- * ## User Data Access
41
- *
42
- * ```ts
43
- * success: async (ctx, value) => {
44
- * if (value.provider === "twitch") {
45
- * const accessToken = value.tokenset.access
46
- *
47
- * // Fetch user information
48
- * const userResponse = await fetch('https://api.twitch.tv/helix/users', {
49
- * headers: {
50
- * 'Authorization': `Bearer ${accessToken}`,
51
- * 'Client-ID': process.env.TWITCH_CLIENT_ID
52
- * }
53
- * })
54
- * const { data } = await userResponse.json()
55
- * const user = data[0]
56
- *
57
- * // User info available: id, login, display_name, email, profile_image_url
58
- * }
59
- * }
60
- * ```
61
- *
62
- * @packageDocumentation
63
- */
64
- /**
65
- * Creates a Twitch OAuth 2.0 authentication provider.
66
- * Allows users to authenticate using their Twitch accounts.
67
- *
68
- * @param config - Twitch OAuth 2.0 configuration
69
- * @returns OAuth 2.0 provider configured for Twitch
70
- *
71
- * @example
72
- * ```ts
73
- * // Basic Twitch authentication
74
- * const basicTwitch = TwitchProvider({
75
- * clientID: process.env.TWITCH_CLIENT_ID,
76
- * clientSecret: process.env.TWITCH_CLIENT_SECRET
77
- * })
78
- *
79
- * // Twitch with email scope
80
- * const twitchWithEmail = TwitchProvider({
81
- * clientID: process.env.TWITCH_CLIENT_ID,
82
- * clientSecret: process.env.TWITCH_CLIENT_SECRET,
83
- * scopes: ["user:read:email"]
84
- * })
85
- *
86
- * // Using the access token to fetch user data
87
- * export default issuer({
88
- * providers: { twitch: twitchWithEmail },
89
- * success: async (ctx, value) => {
90
- * if (value.provider === "twitch") {
91
- * const token = value.tokenset.access
92
- *
93
- * const userRes = await fetch('https://api.twitch.tv/helix/users', {
94
- * headers: {
95
- * 'Authorization': `Bearer ${token}`,
96
- * 'Client-ID': process.env.TWITCH_CLIENT_ID
97
- * }
98
- * })
99
- * const { data } = await userRes.json()
100
- * const user = data[0]
101
- *
102
- * return ctx.subject("user", {
103
- * twitchId: user.id,
104
- * login: user.login,
105
- * email: user.email,
106
- * displayName: user.display_name
107
- * })
108
- * }
109
- * }
110
- * })
111
- * ```
112
- *
113
- * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
114
- * - Development: `http://localhost:3000/auth/twitch/callback`
115
- * - Production: `https://yourapp.com/auth/twitch/callback`
116
- *
117
- * Register this URL in your Twitch Developer Console.
118
- */
119
- const TwitchProvider = (config) => {
120
- return Oauth2Provider({
121
- ...config,
122
- type: "twitch",
123
- endpoint: {
124
- authorization: "https://id.twitch.tv/oauth2/authorize",
125
- token: "https://id.twitch.tv/oauth2/token"
126
- }
127
- });
128
- };
129
-
130
- //#endregion
131
- export { TwitchProvider };