@authcore/core 0.6.0 → 0.12.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 (87) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +141 -125
  3. package/dist/auth.d.ts +141 -13
  4. package/dist/auth.d.ts.map +1 -1
  5. package/dist/auth.js +265 -7
  6. package/dist/auth.js.map +1 -1
  7. package/dist/features/emailVerification.d.ts +6 -2
  8. package/dist/features/emailVerification.d.ts.map +1 -1
  9. package/dist/features/emailVerification.js +7 -10
  10. package/dist/features/emailVerification.js.map +1 -1
  11. package/dist/features/invitation.d.ts +7 -2
  12. package/dist/features/invitation.d.ts.map +1 -1
  13. package/dist/features/invitation.js +7 -9
  14. package/dist/features/invitation.js.map +1 -1
  15. package/dist/features/magicLink.d.ts +56 -0
  16. package/dist/features/magicLink.d.ts.map +1 -0
  17. package/dist/features/magicLink.js +88 -0
  18. package/dist/features/magicLink.js.map +1 -0
  19. package/dist/features/oauth.d.ts +39 -0
  20. package/dist/features/oauth.d.ts.map +1 -0
  21. package/dist/features/oauth.js +161 -0
  22. package/dist/features/oauth.js.map +1 -0
  23. package/dist/features/passwordReset.d.ts +6 -2
  24. package/dist/features/passwordReset.d.ts.map +1 -1
  25. package/dist/features/passwordReset.js +7 -10
  26. package/dist/features/passwordReset.js.map +1 -1
  27. package/dist/features/refresh.d.ts +41 -0
  28. package/dist/features/refresh.d.ts.map +1 -0
  29. package/dist/features/refresh.js +58 -0
  30. package/dist/features/refresh.js.map +1 -0
  31. package/dist/features/templates.d.ts +46 -0
  32. package/dist/features/templates.d.ts.map +1 -0
  33. package/dist/features/templates.js +67 -0
  34. package/dist/features/templates.js.map +1 -0
  35. package/dist/features/twoFactor.d.ts +72 -0
  36. package/dist/features/twoFactor.d.ts.map +1 -0
  37. package/dist/features/twoFactor.js +119 -0
  38. package/dist/features/twoFactor.js.map +1 -0
  39. package/dist/index.d.ts +22 -8
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +14 -2
  42. package/dist/index.js.map +1 -1
  43. package/dist/oauth/apple.d.ts +80 -0
  44. package/dist/oauth/apple.d.ts.map +1 -0
  45. package/dist/oauth/apple.js +148 -0
  46. package/dist/oauth/apple.js.map +1 -0
  47. package/dist/oauth/discord.d.ts +32 -0
  48. package/dist/oauth/discord.d.ts.map +1 -0
  49. package/dist/oauth/discord.js +86 -0
  50. package/dist/oauth/discord.js.map +1 -0
  51. package/dist/oauth/github.d.ts +35 -0
  52. package/dist/oauth/github.d.ts.map +1 -0
  53. package/dist/oauth/github.js +114 -0
  54. package/dist/oauth/github.js.map +1 -0
  55. package/dist/oauth/google.d.ts +21 -0
  56. package/dist/oauth/google.d.ts.map +1 -0
  57. package/dist/oauth/google.js +76 -0
  58. package/dist/oauth/google.js.map +1 -0
  59. package/dist/oauth/microsoft.d.ts +40 -0
  60. package/dist/oauth/microsoft.d.ts.map +1 -0
  61. package/dist/oauth/microsoft.js +126 -0
  62. package/dist/oauth/microsoft.js.map +1 -0
  63. package/dist/utils/token.d.ts +37 -0
  64. package/dist/utils/token.d.ts.map +1 -1
  65. package/dist/utils/token.js +53 -0
  66. package/dist/utils/token.js.map +1 -1
  67. package/dist/utils/totp.d.ts +59 -0
  68. package/dist/utils/totp.d.ts.map +1 -0
  69. package/dist/utils/totp.js +176 -0
  70. package/dist/utils/totp.js.map +1 -0
  71. package/dist/utils/validation.d.ts +18 -0
  72. package/dist/utils/validation.d.ts.map +1 -1
  73. package/dist/utils/validation.js +8 -0
  74. package/dist/utils/validation.js.map +1 -1
  75. package/package.json +4 -3
  76. package/dist/adapters/database.interface.d.ts +0 -42
  77. package/dist/adapters/database.interface.d.ts.map +0 -1
  78. package/dist/adapters/database.interface.js +0 -2
  79. package/dist/adapters/database.interface.js.map +0 -1
  80. package/dist/adapters/email.interface.d.ts +0 -31
  81. package/dist/adapters/email.interface.d.ts.map +0 -1
  82. package/dist/adapters/email.interface.js +0 -2
  83. package/dist/adapters/email.interface.js.map +0 -1
  84. package/dist/types.d.ts +0 -76
  85. package/dist/types.d.ts.map +0 -1
  86. package/dist/types.js +0 -6
  87. package/dist/types.js.map +0 -1
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 David Ouatedem
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 David Ouatedem
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,125 +1,141 @@
1
- # @authcore/core
2
-
3
- > Framework-agnostic authentication engine. Types, validation, password hashing, JWT, and adapter interfaces.
4
-
5
- This is the core package that powers all AuthCore framework adapters. You typically won't use it directly. Use [`@authcore/express`](https://www.npmjs.com/package/@authcore/express) or [`@authcore/fastify`](https://www.npmjs.com/package/@authcore/fastify) instead.
6
-
7
- ## Install
8
-
9
- ```bash
10
- npm install @authcore/core
11
- ```
12
-
13
- ## What's Inside
14
-
15
- ### `createAuth(config)`
16
-
17
- The main factory that creates an auth instance with `register`, `login`, `verifyToken`, `verifyEmail`, `forgotPassword`, `resetPassword`, `invite`, and `acceptInvitation` methods.
18
-
19
- ```ts
20
- import { createAuth } from '@authcore/core'
21
-
22
- const auth = createAuth({
23
- db: myDatabaseAdapter,
24
- session: { strategy: 'jwt', secret: 'your-secret', expiresIn: '7d' },
25
- email: { provider: myEmailAdapter, from: 'auth@example.com' },
26
- features: ['emailVerification', 'passwordReset', 'invitation'],
27
- password: { minLength: 8 },
28
- rbac: { defaultRole: 'user' },
29
- callbacks: {
30
- onSignUp: (user) => { /* ... */ },
31
- onSignIn: (user) => { /* ... */ },
32
- },
33
- })
34
-
35
- const { user, token } = await auth.register({ email: 'user@example.com', password: 'securepass' })
36
- const { user, token } = await auth.login({ email: 'user@example.com', password: 'securepass' })
37
- const publicUser = await auth.verifyToken(token)
38
- ```
39
-
40
- ### Adapter Interfaces
41
-
42
- Implement these to add support for any database or email provider:
43
-
44
- ```ts
45
- import type { DatabaseAdapter, EmailAdapter } from '@authcore/core'
46
- ```
47
-
48
- **DatabaseAdapter:**
49
-
50
- ```ts
51
- interface DatabaseAdapter {
52
- findUserByEmail(email: string): Promise<User | null>
53
- findUserById(id: string): Promise<User | null>
54
- createUser(data: CreateUserInput): Promise<User>
55
- updateUser(id: string, data: Partial<User>): Promise<User>
56
- createToken(data: CreateTokenInput): Promise<Token>
57
- findToken(rawToken: string, type: TokenType): Promise<Token | null>
58
- deleteToken(id: string): Promise<void>
59
- deleteExpiredTokens(): Promise<void>
60
- }
61
- ```
62
-
63
- **EmailAdapter:**
64
-
65
- ```ts
66
- interface EmailAdapter {
67
- send(options: { from: string; to: string; subject: string; html: string; text: string }): Promise<void>
68
- }
69
- ```
70
-
71
- ### Types
72
-
73
- ```ts
74
- import type {
75
- User,
76
- PublicUser,
77
- Token,
78
- TokenType,
79
- AuthCoreConfig,
80
- AuthCore,
81
- DatabaseAdapter,
82
- EmailAdapter,
83
- AuthError,
84
- } from '@authcore/core'
85
- ```
86
-
87
- ### Utilities
88
-
89
- ```ts
90
- import {
91
- hashPassword,
92
- verifyPassword,
93
- generateOpaqueToken,
94
- hashToken,
95
- safeCompareTokens,
96
- signJwt,
97
- verifyJwt,
98
- } from '@authcore/core'
99
- ```
100
-
101
- ### Validation Schemas (Zod)
102
-
103
- ```ts
104
- import {
105
- registerSchema,
106
- loginSchema,
107
- forgotPasswordSchema,
108
- resetPasswordSchema,
109
- verifyEmailSchema,
110
- inviteSchema,
111
- acceptInvitationSchema,
112
- } from '@authcore/core'
113
- ```
114
-
115
- ### RBAC
116
-
117
- Users have a `role` field (string). The default role for new registrations is `'user'`, configurable via `rbac.defaultRole`. The role is included in the JWT payload, so role checks don't need extra database lookups.
118
-
119
- ### Invitation
120
-
121
- Enable the `'invitation'` feature to let authenticated users invite new users by email. The invited user receives a link to set their password and activate their account. Invitation tokens expire in 48 hours.
122
-
123
- ## License
124
-
125
- [MIT](https://github.com/david-ouatedem/auth-core/blob/main/LICENSE)
1
+ # @authcore/core
2
+
3
+ > Framework-agnostic authentication engine. Types, validation, password hashing, JWT, and adapter interfaces.
4
+
5
+ This is the core package that powers all AuthCore framework adapters. You typically won't use it directly. Use [`@authcore/express`](https://www.npmjs.com/package/@authcore/express) or [`@authcore/fastify`](https://www.npmjs.com/package/@authcore/fastify) instead.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @authcore/core
11
+ ```
12
+
13
+ ## What's Inside
14
+
15
+ ### `createAuth(config)`
16
+
17
+ The main factory that creates an auth instance with `register`, `login`, `verifyToken`, `verifyEmail`, `forgotPassword`, `resetPassword`, `invite`, `acceptInvitation`, `refresh`, `revoke`, and `revokeAll` methods.
18
+
19
+ ```ts
20
+ import { createAuth } from '@authcore/core'
21
+
22
+ const auth = createAuth({
23
+ db: myDatabaseAdapter,
24
+ session: {
25
+ strategy: 'jwt',
26
+ secret: 'your-secret',
27
+ expiresIn: '7d',
28
+ cookieName: 'my_token', // optional; default 'authcore_token'
29
+ },
30
+ email: { provider: myEmailAdapter, from: 'auth@example.com' },
31
+ features: ['emailVerification', 'passwordReset', 'invitation'],
32
+ password: { minLength: 8 },
33
+ rbac: { defaultRole: 'user' },
34
+ callbacks: {
35
+ onSignUp: (user) => { /* ... */ },
36
+ onSignIn: (user) => { /* ... */ },
37
+ },
38
+ })
39
+
40
+ const { user, token } = await auth.register({ email: 'user@example.com', password: 'securepass' })
41
+ const { user, token } = await auth.login({ email: 'user@example.com', password: 'securepass' })
42
+ const publicUser = await auth.verifyToken(token)
43
+
44
+ // Direct-core callers MUST pass a resetUrl. Framework adapters do this for you.
45
+ await auth.forgotPassword(
46
+ { email: 'user@example.com' },
47
+ { resetUrl: 'https://app.example.com/reset-password' },
48
+ )
49
+
50
+ // The resolved config is exposed so framework adapters can read session.cookieName, etc.
51
+ console.log(auth.config.session.cookieName)
52
+ ```
53
+
54
+ > **Breaking change in 0.9 (direct-core callers only):** `auth.forgotPassword(input)` is now `auth.forgotPassword(input, { resetUrl })`. The framework adapters (`@authcore/express`, `@authcore/fastify`, `@authcore/nestjs`) build the URL automatically from `baseUrl + paths.resetPassword`, so apps using those packages are unaffected. Direct-core callers must add the second argument or `forgotPassword` throws `AuthError('resetUrl is required', 'MISSING_URL', 500)`. This is a deliberate loud failure that replaces the pre-0.9 silent leak of `session.secret` into reset-email URLs.
55
+
56
+ ### Adapter Interfaces
57
+
58
+ Implement these to add support for any database or email provider:
59
+
60
+ ```ts
61
+ import type { DatabaseAdapter, EmailAdapter } from '@authcore/core'
62
+ ```
63
+
64
+ **DatabaseAdapter:**
65
+
66
+ ```ts
67
+ interface DatabaseAdapter {
68
+ findUserByEmail(email: string): Promise<User | null>
69
+ findUserById(id: string): Promise<User | null>
70
+ createUser(data: CreateUserInput): Promise<User>
71
+ updateUser(id: string, data: Partial<User>): Promise<User>
72
+ createToken(data: CreateTokenInput): Promise<Token>
73
+ findToken(rawToken: string, type: TokenType): Promise<Token | null>
74
+ deleteToken(id: string): Promise<void>
75
+ deleteExpiredTokens(): Promise<void>
76
+ }
77
+ ```
78
+
79
+ **EmailAdapter:**
80
+
81
+ ```ts
82
+ interface EmailAdapter {
83
+ send(options: { from: string; to: string; subject: string; html: string; text: string }): Promise<void>
84
+ }
85
+ ```
86
+
87
+ ### Types
88
+
89
+ ```ts
90
+ import type {
91
+ User,
92
+ PublicUser,
93
+ Token,
94
+ TokenType,
95
+ AuthCoreConfig,
96
+ AuthCore,
97
+ DatabaseAdapter,
98
+ EmailAdapter,
99
+ AuthError,
100
+ } from '@authcore/core'
101
+ ```
102
+
103
+ ### Utilities
104
+
105
+ ```ts
106
+ import {
107
+ hashPassword,
108
+ verifyPassword,
109
+ generateOpaqueToken,
110
+ hashToken,
111
+ safeCompareTokens,
112
+ signJwt,
113
+ verifyJwt,
114
+ } from '@authcore/core'
115
+ ```
116
+
117
+ ### Validation Schemas (Zod)
118
+
119
+ ```ts
120
+ import {
121
+ registerSchema,
122
+ loginSchema,
123
+ forgotPasswordSchema,
124
+ resetPasswordSchema,
125
+ verifyEmailSchema,
126
+ inviteSchema,
127
+ acceptInvitationSchema,
128
+ } from '@authcore/core'
129
+ ```
130
+
131
+ ### RBAC
132
+
133
+ Users have a `role` field (string). The default role for new registrations is `'user'`, configurable via `rbac.defaultRole`. The role is included in the JWT payload, so role checks don't need extra database lookups.
134
+
135
+ ### Invitation
136
+
137
+ Enable the `'invitation'` feature to let authenticated users invite new users by email. The invited user receives a link to set their password and activate their account. Invitation tokens expire in 48 hours.
138
+
139
+ ## License
140
+
141
+ [MIT](https://github.com/david-ouatedem/auth-core/blob/main/LICENSE)
package/dist/auth.d.ts CHANGED
@@ -1,30 +1,45 @@
1
- import type { AuthCoreConfig, PublicUser } from './types.js';
1
+ import type { AuthCoreConfig, PublicUser } from '@authcore/types';
2
2
  export declare class AuthError extends Error {
3
3
  readonly code: string;
4
4
  readonly statusCode: number;
5
5
  constructor(message: string, code: string, statusCode: number);
6
6
  }
7
+ /** Successful authentication — full session minted. */
8
+ export interface SessionResult {
9
+ user: PublicUser;
10
+ token: string;
11
+ refreshToken: string;
12
+ }
13
+ /** First-factor passed, awaiting TOTP / recovery code. */
14
+ export interface TwoFactorChallengeResult {
15
+ requires2FA: true;
16
+ /** Short-lived JWT (5 min default) to pass back to `verifyTwoFactor` / `useRecoveryCode`. */
17
+ challengeToken: string;
18
+ }
19
+ /** Login result is either a full session or a 2FA challenge. */
20
+ export type LoginResult = SessionResult | TwoFactorChallengeResult;
7
21
  /**
8
22
  * The AuthCore instance returned by createAuth.
9
- * Framework adapters (Express, Fastify) wrap this object.
23
+ * Framework adapters (Express, Fastify, NestJS, Next.js) wrap this object.
10
24
  */
11
25
  export interface AuthCore {
12
26
  /**
13
27
  * Register a new user.
14
28
  * @throws AuthError on validation failure (400) or duplicate email (409)
15
29
  */
16
- register(input: unknown): Promise<{
17
- user: PublicUser;
18
- token: string;
19
- }>;
30
+ register(input: unknown): Promise<SessionResult>;
20
31
  /**
21
32
  * Authenticate a user with email/password.
33
+ *
34
+ * Returns a discriminated union — narrow on `'requires2FA' in result`:
35
+ * - **Session**: `{ user, token, refreshToken }` when 2FA is off for that user.
36
+ * - **Challenge**: `{ requires2FA: true, challengeToken }` when 2FA is on. Pass
37
+ * the `challengeToken` to {@link verifyTwoFactor} or {@link useRecoveryCode}
38
+ * along with the user's code to complete the login.
39
+ *
22
40
  * @throws AuthError on invalid credentials (401)
23
41
  */
24
- login(input: unknown): Promise<{
25
- user: PublicUser;
26
- token: string;
27
- }>;
42
+ login(input: unknown): Promise<LoginResult>;
28
43
  /**
29
44
  * Verify a JWT and return the public user.
30
45
  * Returns null if the token is invalid or expired.
@@ -45,9 +60,14 @@ export interface AuthCore {
45
60
  */
46
61
  verifyEmail(input: unknown): Promise<void>;
47
62
  /**
48
- * Initiate password reset. Always returns successfully (prevents enumeration).
63
+ * Initiate password reset. Always returns successfully when called via a framework
64
+ * adapter (prevents email enumeration). Throws `MISSING_URL` (500) if called directly
65
+ * without a `resetUrl`. Framework adapters always supply one built from baseUrl +
66
+ * the configured reset-password route.
49
67
  */
50
- forgotPassword(input: unknown): Promise<void>;
68
+ forgotPassword(input: unknown, params?: {
69
+ resetUrl: string;
70
+ }): Promise<void>;
51
71
  /**
52
72
  * Complete password reset using the raw token.
53
73
  * @throws AuthError if token is invalid or expired (400)
@@ -65,10 +85,118 @@ export interface AuthCore {
65
85
  * Accept an invitation by setting a password.
66
86
  * @throws AuthError if token is invalid or expired (400)
67
87
  */
68
- acceptInvitation(input: unknown): Promise<{
88
+ acceptInvitation(input: unknown): Promise<SessionResult>;
89
+ /**
90
+ * Exchange a refresh token for a new JWT + a freshly rotated refresh token.
91
+ * The old refresh token is invalidated atomically.
92
+ * @throws AuthError(401, 'INVALID_TOKEN') if the refresh token is missing, invalid, or expired
93
+ */
94
+ refresh(rawRefreshToken: string): Promise<SessionResult>;
95
+ /**
96
+ * Revoke a single refresh token. Idempotent — succeeds even if the token doesn't exist.
97
+ */
98
+ revoke(rawRefreshToken: string): Promise<void>;
99
+ /**
100
+ * Revoke every outstanding refresh token for a user ("log out everywhere").
101
+ */
102
+ revokeAll(userId: string): Promise<void>;
103
+ /**
104
+ * Send a magic-link email. Always resolves successfully — does not reveal
105
+ * whether the email exists in the database (enumeration-safe). By default
106
+ * a new user is auto-created if none exists; the email is marked verified
107
+ * because receipt of the link proves email ownership.
108
+ *
109
+ * Requires the `magicLink` feature flag and a configured email provider.
110
+ *
111
+ * @throws AuthError(500, 'FEATURE_DISABLED') if the feature flag is off.
112
+ * @throws AuthError(500, 'EMAIL_NOT_CONFIGURED') if no email provider is set.
113
+ * @throws AuthError(500, 'MISSING_URL') if `magicLinkUrl` is not supplied.
114
+ */
115
+ sendMagicLink(input: unknown, params: {
116
+ magicLinkUrl: string;
117
+ }): Promise<void>;
118
+ /**
119
+ * Consume a magic-link token. Returns a full session: user + JWT + refresh.
120
+ * Tokens are single-use; a second call with the same raw token throws.
121
+ * @throws AuthError(400, 'INVALID_TOKEN') if the token is unknown or expired.
122
+ */
123
+ consumeMagicLink(input: unknown): Promise<{
69
124
  user: PublicUser;
70
125
  token: string;
126
+ refreshToken: string;
127
+ }>;
128
+ /**
129
+ * Begin an OAuth flow with the provider registered under the given id (e.g. 'google').
130
+ * Returns the authorization URL the user must be redirected to.
131
+ * @throws AuthError if the provider isn't registered in `config.oauth`.
132
+ */
133
+ oauthStart(providerId: string, redirectUri: string): Promise<{
134
+ authorizationUrl: string;
135
+ state: string;
136
+ }>;
137
+ /**
138
+ * Complete an OAuth callback. Validates state, exchanges code for tokens, links or creates
139
+ * the user according to the auto-link policy (email-verified only).
140
+ * @throws AuthError on invalid state (401), EMAIL_NOT_VERIFIED_BY_PROVIDER (409), or
141
+ * upstream provider failure (502).
142
+ */
143
+ oauthCallback(providerId: string, params: {
144
+ code: string;
145
+ state: string;
146
+ redirectUri: string;
147
+ }): Promise<SessionResult & {
148
+ isNewUser: boolean;
149
+ }>;
150
+ /**
151
+ * Begin 2FA enrollment. Returns the new TOTP secret, an `otpauth://` URL
152
+ * suitable for QR rendering, and 10 single-use recovery codes the user
153
+ * MUST store. Calls this method overwrite any prior unconfirmed setup.
154
+ *
155
+ * The secret is persisted on the user with `twoFactorEnabled` still
156
+ * `false` — call {@link enableTwoFactor} with the first generated code to
157
+ * flip the flag.
158
+ *
159
+ * @throws AuthError(404, 'USER_NOT_FOUND') if the user does not exist.
160
+ */
161
+ setupTwoFactor(userId: string): Promise<{
162
+ secret: string;
163
+ otpauthUrl: string;
164
+ recoveryCodes: string[];
71
165
  }>;
166
+ /**
167
+ * Confirm 2FA enrollment by verifying the first authenticator code.
168
+ * @throws AuthError(400, 'TWO_FACTOR_NOT_SET_UP') if setup hasn't run.
169
+ * @throws AuthError(400, 'INVALID_TWO_FACTOR_CODE') on a wrong code.
170
+ */
171
+ enableTwoFactor(userId: string, code: string): Promise<void>;
172
+ /**
173
+ * Disable 2FA for the user. Requires the user's current password as a
174
+ * confirmation step (prevents an attacker with a stolen session cookie from
175
+ * silently turning off 2FA).
176
+ *
177
+ * @throws AuthError(401, 'INVALID_CREDENTIALS') if the password is wrong.
178
+ * @throws AuthError(404, 'USER_NOT_FOUND') if the user does not exist.
179
+ */
180
+ disableTwoFactor(userId: string, password: string): Promise<void>;
181
+ /**
182
+ * Complete a 2FA-pending login. Pass the `challengeToken` from {@link login}
183
+ * along with the user's current TOTP code.
184
+ *
185
+ * @throws AuthError(401, 'INVALID_TOKEN') if the challenge JWT is invalid or expired.
186
+ * @throws AuthError(401, 'INVALID_TWO_FACTOR_CODE') if the TOTP code is wrong.
187
+ */
188
+ verifyTwoFactor(challengeToken: string, code: string): Promise<SessionResult>;
189
+ /**
190
+ * Complete a 2FA-pending login using a single-use recovery code. Same
191
+ * challenge flow as {@link verifyTwoFactor}; the matching recovery code is
192
+ * deleted before the session is returned.
193
+ *
194
+ * @throws AuthError(401, 'INVALID_TOKEN') if the challenge JWT is invalid or expired.
195
+ * @throws AuthError(401, 'INVALID_RECOVERY_CODE') if the code is unknown.
196
+ */
197
+ useRecoveryCode(challengeToken: string, code: string): Promise<SessionResult>;
198
+ /** The resolved configuration this instance was created with. */
199
+ readonly config: AuthCoreConfig;
72
200
  }
73
201
  /**
74
202
  * Create an AuthCore instance from the provided configuration.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAwB5D,qBAAa,SAAU,SAAQ,KAAK;aAGhB,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;gBAFlC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM;CAKrC;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAEtE;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAEnE;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;IAEtD;;;OAGG;IACH,qBAAqB,CAAC,MAAM,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;QACb,eAAe,EAAE,MAAM,CAAA;KACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjB;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE1C;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE7C;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE5C;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEpE;;;OAGG;IACH,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC/E;AAqBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,CA8P3D"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}