@nexusrt/nexus-auth 1.0.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/README.md +277 -0
- package/dist/client.d.ts +106 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/http.d.ts +11 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/index.d.mts +466 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +613 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +506 -0
- package/dist/methods/emailMfa.d.ts +18 -0
- package/dist/methods/emailMfa.d.ts.map +1 -0
- package/dist/methods/emailPassword.d.ts +52 -0
- package/dist/methods/emailPassword.d.ts.map +1 -0
- package/dist/methods/magicLink.d.ts +27 -0
- package/dist/methods/magicLink.d.ts.map +1 -0
- package/dist/methods/password.d.ts +37 -0
- package/dist/methods/password.d.ts.map +1 -0
- package/dist/methods/session.d.ts +27 -0
- package/dist/methods/session.d.ts.map +1 -0
- package/dist/methods/sso.d.ts +34 -0
- package/dist/methods/sso.d.ts.map +1 -0
- package/dist/methods/token.d.ts +32 -0
- package/dist/methods/token.d.ts.map +1 -0
- package/dist/methods/totp.d.ts +34 -0
- package/dist/methods/totp.d.ts.map +1 -0
- package/dist/providers/social.d.ts +23 -0
- package/dist/providers/social.d.ts.map +1 -0
- package/dist/types/index.d.ts +92 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +43 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
// src/http.ts
|
|
2
|
+
async function request(url, options = {}) {
|
|
3
|
+
const response = await fetch(url, {
|
|
4
|
+
...options,
|
|
5
|
+
credentials: "include",
|
|
6
|
+
// required for cookie-based sessions
|
|
7
|
+
headers: {
|
|
8
|
+
"Content-Type": "application/json",
|
|
9
|
+
...options.headers
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
const data = await response.json().catch(() => null);
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
const message = data?.message ?? `Request failed with status ${response.status}`;
|
|
15
|
+
throw new AuthError(message, response.status, data);
|
|
16
|
+
}
|
|
17
|
+
return data;
|
|
18
|
+
}
|
|
19
|
+
var AuthError = class extends Error {
|
|
20
|
+
constructor(message, status, body = null) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.status = status;
|
|
23
|
+
this.body = body;
|
|
24
|
+
this.name = "AuthError";
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/methods/token.ts
|
|
29
|
+
var TokenManager = class {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.accessToken = null;
|
|
32
|
+
}
|
|
33
|
+
// ── Getters / Setters ───────────────────────────────────────────────────
|
|
34
|
+
getAccessToken() {
|
|
35
|
+
return this.accessToken;
|
|
36
|
+
}
|
|
37
|
+
setAccessToken(token) {
|
|
38
|
+
this.accessToken = token;
|
|
39
|
+
}
|
|
40
|
+
clearAccessToken() {
|
|
41
|
+
this.accessToken = null;
|
|
42
|
+
}
|
|
43
|
+
// ── JWT helpers ─────────────────────────────────────────────────────────
|
|
44
|
+
/**
|
|
45
|
+
* Decodes the JWT payload without verifying the signature.
|
|
46
|
+
* Useful for reading user info (email, avatar) on the client side.
|
|
47
|
+
*/
|
|
48
|
+
decodeToken(token) {
|
|
49
|
+
try {
|
|
50
|
+
const payload = token.split(".")[1];
|
|
51
|
+
return JSON.parse(atob(payload));
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Reads user info directly from the stored access token.
|
|
58
|
+
* Returns null if no token is set or it cannot be decoded.
|
|
59
|
+
*/
|
|
60
|
+
getUserFromToken() {
|
|
61
|
+
if (!this.accessToken) return null;
|
|
62
|
+
const payload = this.decodeToken(this.accessToken);
|
|
63
|
+
if (!payload) return null;
|
|
64
|
+
return {
|
|
65
|
+
email: payload.email,
|
|
66
|
+
avatar_url: payload.avatar_url
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// ── Refresh ─────────────────────────────────────────────────────────────
|
|
70
|
+
/**
|
|
71
|
+
* Attempts to get a new access token using the HttpOnly refresh-token cookie.
|
|
72
|
+
* Call this once on app startup to restore an existing session.
|
|
73
|
+
*
|
|
74
|
+
* @returns The decoded user info on success, or null if no refresh token exists.
|
|
75
|
+
*/
|
|
76
|
+
async refresh(baseUrl) {
|
|
77
|
+
try {
|
|
78
|
+
const data = await request(
|
|
79
|
+
`${baseUrl}/auth/refresh`,
|
|
80
|
+
{ method: "POST" }
|
|
81
|
+
);
|
|
82
|
+
this.setAccessToken(data.access_token);
|
|
83
|
+
return this.getUserFromToken();
|
|
84
|
+
} catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// src/methods/session.ts
|
|
91
|
+
var SessionManager = class {
|
|
92
|
+
// ── Get Current User ────────────────────────────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* Fetches the currently authenticated user from the server.
|
|
95
|
+
* Relies on the session cookie being present in the browser.
|
|
96
|
+
*
|
|
97
|
+
* Use this instead of decoding the JWT when you want the
|
|
98
|
+
* authoritative user object from your database.
|
|
99
|
+
*/
|
|
100
|
+
async getUser(baseUrl) {
|
|
101
|
+
return request(`${baseUrl}/me`, { method: "GET" });
|
|
102
|
+
}
|
|
103
|
+
// ── Verify Session ──────────────────────────────────────────────────────
|
|
104
|
+
/**
|
|
105
|
+
* Verifies that a session is still valid for a given email address.
|
|
106
|
+
* Useful for server-side checks or sensitive operations.
|
|
107
|
+
*/
|
|
108
|
+
async verifySession(baseUrl, email) {
|
|
109
|
+
await request(`${baseUrl}/auth/verify_session`, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
body: JSON.stringify({ email })
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// src/types/index.ts
|
|
117
|
+
var SignInStatus = {
|
|
118
|
+
/** Standard email+password sign-in succeeded — no MFA required */
|
|
119
|
+
SUCCESS: "SUCCESS",
|
|
120
|
+
/** Server requires the user to complete an Email MFA challenge */
|
|
121
|
+
MFA_REQUIRED: "MFA_REQUIRED",
|
|
122
|
+
/** Server requires the user to complete a TOTP challenge */
|
|
123
|
+
TOTP_REQUIRED: "TOTP_REQUIRED",
|
|
124
|
+
/** Server sent a magic link/code to the user's email */
|
|
125
|
+
MAGIC_LINK: "MAGIC_LINK",
|
|
126
|
+
/** Server sent a password-reset code to the user's email */
|
|
127
|
+
RESET_PASSWORD: "RESET_PASSWORD"
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// src/methods/emailPassword.ts
|
|
131
|
+
var EmailPasswordAuth = class {
|
|
132
|
+
// ── Sign Up ─────────────────────────────────────────────────────────────
|
|
133
|
+
/**
|
|
134
|
+
* Creates a new account with an email address and password.
|
|
135
|
+
*/
|
|
136
|
+
async signUp(baseUrl, credentials) {
|
|
137
|
+
return request(
|
|
138
|
+
`${baseUrl}/auth/email_password/signup`,
|
|
139
|
+
{
|
|
140
|
+
method: "POST",
|
|
141
|
+
body: JSON.stringify({
|
|
142
|
+
email: credentials.email,
|
|
143
|
+
password: credentials.password,
|
|
144
|
+
userName: credentials.userName,
|
|
145
|
+
firstName: credentials.firstName,
|
|
146
|
+
lastName: credentials.lastName
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
// ── Sign In ─────────────────────────────────────────────────────────────
|
|
152
|
+
/**
|
|
153
|
+
* Signs in with email + password.
|
|
154
|
+
*
|
|
155
|
+
* Check `response.status` to determine the next step:
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* const result = await auth.email.signIn({ email, password });
|
|
159
|
+
*
|
|
160
|
+
* if (result.status === SignInStatus.MFA_REQUIRED) {
|
|
161
|
+
* // prompt for email OTP, then call auth.email.verifyMfa()
|
|
162
|
+
* } else if (result.status === SignInStatus.TOTP_REQUIRED) {
|
|
163
|
+
* // prompt for TOTP code, then call auth.totp.verifySignIn()
|
|
164
|
+
* } else {
|
|
165
|
+
* // user is signed in — store result.access_token if using JWT mode
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
async signIn(baseUrl, credentials) {
|
|
170
|
+
return request(
|
|
171
|
+
`${baseUrl}/auth/email_password/signin`,
|
|
172
|
+
{
|
|
173
|
+
method: "POST",
|
|
174
|
+
body: JSON.stringify({
|
|
175
|
+
email: credentials.email,
|
|
176
|
+
password: credentials.password
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
// ── Email MFA verify ────────────────────────────────────────────────────
|
|
182
|
+
/**
|
|
183
|
+
* Confirms the one-time code sent to the user's email after a sign-in
|
|
184
|
+
* that returned `status === SignInStatus.MFA_REQUIRED`.
|
|
185
|
+
*/
|
|
186
|
+
async verifyMfa(baseUrl, input) {
|
|
187
|
+
return request(
|
|
188
|
+
`${baseUrl}/auth/email_mfa_signin`,
|
|
189
|
+
{
|
|
190
|
+
method: "POST",
|
|
191
|
+
body: JSON.stringify({
|
|
192
|
+
sessionid: input.sessionId,
|
|
193
|
+
code: input.code
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
// ── Get username ────────────────────────────────────────────────────────
|
|
199
|
+
/**
|
|
200
|
+
* Looks up the username associated with an email address.
|
|
201
|
+
*/
|
|
202
|
+
async getUsername(baseUrl, email) {
|
|
203
|
+
return request(
|
|
204
|
+
`${baseUrl}/auth/getusername`,
|
|
205
|
+
{
|
|
206
|
+
method: "POST",
|
|
207
|
+
body: JSON.stringify({ email })
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// src/methods/magicLink.ts
|
|
214
|
+
var MagicLinkAuth = class {
|
|
215
|
+
/**
|
|
216
|
+
* Sends a magic-link code to the provided email address.
|
|
217
|
+
*
|
|
218
|
+
* @returns A session ID (`mfa` field) that you must pass to `verify()`.
|
|
219
|
+
*
|
|
220
|
+
* ```ts
|
|
221
|
+
* const { mfa: sessionId } = await auth.magicLink.send(email);
|
|
222
|
+
* // store sessionId, prompt user for code
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
async send(baseUrl, email) {
|
|
226
|
+
return request(
|
|
227
|
+
`${baseUrl}/auth/email_magic_link`,
|
|
228
|
+
{
|
|
229
|
+
method: "POST",
|
|
230
|
+
body: JSON.stringify({ email })
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Verifies the code the user received and completes sign-in.
|
|
236
|
+
*/
|
|
237
|
+
async verify(baseUrl, input) {
|
|
238
|
+
return request(
|
|
239
|
+
`${baseUrl}/auth/verify_magic_link`,
|
|
240
|
+
{
|
|
241
|
+
method: "POST",
|
|
242
|
+
body: JSON.stringify({
|
|
243
|
+
sessionid: input.sessionId,
|
|
244
|
+
code: input.code
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// src/methods/totp.ts
|
|
252
|
+
var TotpAuth = class {
|
|
253
|
+
/**
|
|
254
|
+
* Starts TOTP registration — returns the secret / QR code to display.
|
|
255
|
+
*/
|
|
256
|
+
async setup(baseUrl) {
|
|
257
|
+
return request(
|
|
258
|
+
`${baseUrl}/auth/mfa/totp/start`,
|
|
259
|
+
{ method: "POST" }
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Confirms the TOTP setup by verifying the first code from the
|
|
264
|
+
* authenticator app.
|
|
265
|
+
*/
|
|
266
|
+
async confirmSetup(baseUrl, code) {
|
|
267
|
+
return request(
|
|
268
|
+
`${baseUrl}/auth/mfa/totp/confirm`,
|
|
269
|
+
{
|
|
270
|
+
method: "POST",
|
|
271
|
+
body: JSON.stringify({ code })
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Completes a TOTP sign-in challenge.
|
|
277
|
+
* Use the `mfa` session ID returned by `emailPassword.signIn()` as `sessionId`.
|
|
278
|
+
*/
|
|
279
|
+
async verifySignIn(baseUrl, input) {
|
|
280
|
+
return request(
|
|
281
|
+
`${baseUrl}/auth/mfa/totp/signin`,
|
|
282
|
+
{
|
|
283
|
+
method: "POST",
|
|
284
|
+
body: JSON.stringify({
|
|
285
|
+
challenge_id: input.sessionId,
|
|
286
|
+
code: input.code
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Removes TOTP from the currently authenticated user's account.
|
|
293
|
+
*/
|
|
294
|
+
async delete(baseUrl) {
|
|
295
|
+
await request(`${baseUrl}/auth/mfa/totp/delete`, { method: "POST" });
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// src/methods/password.ts
|
|
300
|
+
var PasswordAuth = class {
|
|
301
|
+
/**
|
|
302
|
+
* Changes the password for an already authenticated user.
|
|
303
|
+
*/
|
|
304
|
+
async reset(baseUrl, input) {
|
|
305
|
+
return request(
|
|
306
|
+
`${baseUrl}/auth/password/reset`,
|
|
307
|
+
{
|
|
308
|
+
method: "POST",
|
|
309
|
+
body: JSON.stringify({
|
|
310
|
+
oldPassword: input.oldPassword,
|
|
311
|
+
newPassword: input.newPassword
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Initiates the forgot-password flow by sending a reset code to the
|
|
318
|
+
* user's email address.
|
|
319
|
+
*
|
|
320
|
+
* @returns A session ID (`mfa` field) required by `confirmForgot()`.
|
|
321
|
+
*
|
|
322
|
+
* ```ts
|
|
323
|
+
* const { mfa: sessionId } = await auth.password.forgot(email);
|
|
324
|
+
* // prompt user for code
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
async forgot(baseUrl, email) {
|
|
328
|
+
return request(
|
|
329
|
+
`${baseUrl}/auth/password/forgot`,
|
|
330
|
+
{
|
|
331
|
+
method: "POST",
|
|
332
|
+
body: JSON.stringify({ email })
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Completes the forgot-password flow by verifying the emailed code
|
|
338
|
+
* and setting the new password.
|
|
339
|
+
*/
|
|
340
|
+
async confirmForgot(baseUrl, input) {
|
|
341
|
+
return request(
|
|
342
|
+
`${baseUrl}/auth/password/forgot/confirm`,
|
|
343
|
+
{
|
|
344
|
+
method: "POST",
|
|
345
|
+
body: JSON.stringify({
|
|
346
|
+
sessionID: input.sessionId,
|
|
347
|
+
code: input.code,
|
|
348
|
+
password: input.password
|
|
349
|
+
})
|
|
350
|
+
}
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// src/methods/sso.ts
|
|
356
|
+
var SsoAuth = class {
|
|
357
|
+
/**
|
|
358
|
+
* Registers an organisation's Identity Provider (IDP) with the auth system.
|
|
359
|
+
* This is typically called once by an organisation admin during onboarding.
|
|
360
|
+
*/
|
|
361
|
+
async registerProvider(baseUrl, input) {
|
|
362
|
+
return request(
|
|
363
|
+
`${baseUrl}/sso/providers/register`,
|
|
364
|
+
{
|
|
365
|
+
method: "POST",
|
|
366
|
+
body: JSON.stringify({
|
|
367
|
+
provider_name: input.providerName,
|
|
368
|
+
provider_end_email: input.providerEndEmail,
|
|
369
|
+
client_id: input.clientId,
|
|
370
|
+
client_secret: input.clientSecret,
|
|
371
|
+
issuer: input.issuer,
|
|
372
|
+
callback_url: input.callbackUrl
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Starts the SSO sign-in flow for an end user.
|
|
379
|
+
*
|
|
380
|
+
* The server resolves the correct IDP from the user's email domain
|
|
381
|
+
* and returns a redirect URL. Redirect the user to that URL to
|
|
382
|
+
* complete sign-in with their organisation's IDP.
|
|
383
|
+
*/
|
|
384
|
+
async signIn(baseUrl, email) {
|
|
385
|
+
return request(`${baseUrl}/sso/start`, {
|
|
386
|
+
method: "POST",
|
|
387
|
+
body: JSON.stringify({ email })
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// src/methods/emailMfa.ts
|
|
393
|
+
var EmailMfaManager = class {
|
|
394
|
+
/**
|
|
395
|
+
* Enables Email MFA for the currently authenticated user.
|
|
396
|
+
* Once enabled, future sign-ins will require a one-time code sent to email.
|
|
397
|
+
*/
|
|
398
|
+
async create(baseUrl) {
|
|
399
|
+
await request(`${baseUrl}/auth/mfa/email/create`, { method: "POST" });
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Disables Email MFA for the currently authenticated user.
|
|
403
|
+
*/
|
|
404
|
+
async delete(baseUrl) {
|
|
405
|
+
await request(`${baseUrl}/auth/mfa/email/delete`, { method: "POST" });
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
// src/providers/social.ts
|
|
410
|
+
var SocialAuth = class {
|
|
411
|
+
constructor(baseUrl) {
|
|
412
|
+
this.baseUrl = baseUrl;
|
|
413
|
+
}
|
|
414
|
+
/** Redirects to Google OAuth sign-in. */
|
|
415
|
+
signInWithGoogle() {
|
|
416
|
+
window.location.href = `${this.baseUrl}/auth/google`;
|
|
417
|
+
}
|
|
418
|
+
/** Redirects to GitHub OAuth sign-in. */
|
|
419
|
+
signInWithGithub() {
|
|
420
|
+
window.location.href = `${this.baseUrl}/auth/github`;
|
|
421
|
+
}
|
|
422
|
+
/** Redirects to LinkedIn OAuth sign-in. */
|
|
423
|
+
signInWithLinkedIn() {
|
|
424
|
+
window.location.href = `${this.baseUrl}/auth/linkedin`;
|
|
425
|
+
}
|
|
426
|
+
/** Redirects to Okta OAuth sign-in. */
|
|
427
|
+
signInWithOkta() {
|
|
428
|
+
window.location.href = `${this.baseUrl}/auth/okta`;
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// src/client.ts
|
|
433
|
+
var AuthClient = class {
|
|
434
|
+
constructor(config = {}) {
|
|
435
|
+
this.baseUrl = config.baseUrl ?? "https://auth.jobtrk.com";
|
|
436
|
+
this.token = new TokenManager();
|
|
437
|
+
this.session = new SessionManager();
|
|
438
|
+
this.social = new SocialAuth(this.baseUrl);
|
|
439
|
+
this.email = new EmailPasswordAuth();
|
|
440
|
+
this.magicLink = new MagicLinkAuth();
|
|
441
|
+
this.totp = new TotpAuth();
|
|
442
|
+
this.emailMfa = new EmailMfaManager();
|
|
443
|
+
this.password = new PasswordAuth();
|
|
444
|
+
this.sso = new SsoAuth();
|
|
445
|
+
}
|
|
446
|
+
// ── Logout helpers ───────────────────────────────────────────────────────
|
|
447
|
+
/**
|
|
448
|
+
* Signs the user out of the current session/device.
|
|
449
|
+
* Clears the in-memory access token after a successful server response.
|
|
450
|
+
*/
|
|
451
|
+
async logout() {
|
|
452
|
+
await request(`${this.baseUrl}/auth/logout`, { method: "POST" });
|
|
453
|
+
this.token.clearAccessToken();
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Signs the user out of ALL active sessions / devices.
|
|
457
|
+
* Clears the in-memory access token after a successful server response.
|
|
458
|
+
*/
|
|
459
|
+
async logoutAllSessions() {
|
|
460
|
+
await request(`${this.baseUrl}/auth/logoutsessions`, { method: "POST" });
|
|
461
|
+
this.token.clearAccessToken();
|
|
462
|
+
}
|
|
463
|
+
// ── Convenience passthrough (avoids needing to pass baseUrl manually) ──
|
|
464
|
+
// The methods below are thin wrappers so callers can write:
|
|
465
|
+
// auth.email.signIn(...) instead of auth.email.signIn(baseUrl, ...)
|
|
466
|
+
// by binding the baseUrl at construction time.
|
|
467
|
+
//
|
|
468
|
+
// This is achieved via Proxy in the factory below, but you can also use
|
|
469
|
+
// the raw modules directly if you prefer more control.
|
|
470
|
+
};
|
|
471
|
+
function bindBaseUrl(module, baseUrl) {
|
|
472
|
+
return new Proxy(module, {
|
|
473
|
+
get(target, prop) {
|
|
474
|
+
const value = target[prop];
|
|
475
|
+
if (typeof value === "function") {
|
|
476
|
+
return (...args) => value.call(target, baseUrl, ...args);
|
|
477
|
+
}
|
|
478
|
+
return value;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
function createAuthClient(config = {}) {
|
|
483
|
+
const baseUrl = config.baseUrl ?? "https://auth.jobtrk.com";
|
|
484
|
+
const client = new AuthClient(config);
|
|
485
|
+
return {
|
|
486
|
+
...client,
|
|
487
|
+
token: bindBaseUrl(client.token, baseUrl),
|
|
488
|
+
session: bindBaseUrl(client.session, baseUrl),
|
|
489
|
+
email: bindBaseUrl(client.email, baseUrl),
|
|
490
|
+
magicLink: bindBaseUrl(client.magicLink, baseUrl),
|
|
491
|
+
totp: bindBaseUrl(client.totp, baseUrl),
|
|
492
|
+
emailMfa: bindBaseUrl(client.emailMfa, baseUrl),
|
|
493
|
+
password: bindBaseUrl(client.password, baseUrl),
|
|
494
|
+
sso: bindBaseUrl(client.sso, baseUrl),
|
|
495
|
+
social: client.social,
|
|
496
|
+
// already has baseUrl from constructor
|
|
497
|
+
logout: () => client.logout(),
|
|
498
|
+
logoutAllSessions: () => client.logoutAllSessions()
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
export {
|
|
502
|
+
AuthClient,
|
|
503
|
+
AuthError,
|
|
504
|
+
SignInStatus,
|
|
505
|
+
createAuthClient
|
|
506
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email MFA management.
|
|
3
|
+
*
|
|
4
|
+
* These methods manage whether a user has Email MFA enabled on their account.
|
|
5
|
+
* They are separate from the sign-in verify step (see EmailPasswordAuth.verifyMfa).
|
|
6
|
+
*/
|
|
7
|
+
export declare class EmailMfaManager {
|
|
8
|
+
/**
|
|
9
|
+
* Enables Email MFA for the currently authenticated user.
|
|
10
|
+
* Once enabled, future sign-ins will require a one-time code sent to email.
|
|
11
|
+
*/
|
|
12
|
+
create(baseUrl: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Disables Email MFA for the currently authenticated user.
|
|
15
|
+
*/
|
|
16
|
+
delete(baseUrl: string): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=emailMfa.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailMfa.d.ts","sourceRoot":"","sources":["../../src/methods/emailMfa.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG7C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { EmailPasswordCredentials, MfaVerifyInput, SignInResponse, GenericSuccessResponse } from "../types";
|
|
2
|
+
import { SignInStatus } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Email + Password authentication methods.
|
|
5
|
+
*
|
|
6
|
+
* Sign-in has three possible outcomes depending on what the user has enabled:
|
|
7
|
+
*
|
|
8
|
+
* 1. Plain sign-in → status is undefined / SUCCESS (no MFA)
|
|
9
|
+
* 2. Email MFA → status === SignInStatus.MFA_REQUIRED
|
|
10
|
+
* 3. TOTP → status === SignInStatus.TOTP_REQUIRED
|
|
11
|
+
*
|
|
12
|
+
* In cases 2 & 3 the response includes a `mfa` session ID that you must
|
|
13
|
+
* pass to the corresponding verify method.
|
|
14
|
+
*
|
|
15
|
+
* Import `SignInStatus` to compare against the status value:
|
|
16
|
+
* import { SignInStatus } from "jobtrk-auth-sdk";
|
|
17
|
+
*/
|
|
18
|
+
export declare class EmailPasswordAuth {
|
|
19
|
+
/**
|
|
20
|
+
* Creates a new account with an email address and password.
|
|
21
|
+
*/
|
|
22
|
+
signUp(baseUrl: string, credentials: EmailPasswordCredentials): Promise<GenericSuccessResponse>;
|
|
23
|
+
/**
|
|
24
|
+
* Signs in with email + password.
|
|
25
|
+
*
|
|
26
|
+
* Check `response.status` to determine the next step:
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* const result = await auth.email.signIn({ email, password });
|
|
30
|
+
*
|
|
31
|
+
* if (result.status === SignInStatus.MFA_REQUIRED) {
|
|
32
|
+
* // prompt for email OTP, then call auth.email.verifyMfa()
|
|
33
|
+
* } else if (result.status === SignInStatus.TOTP_REQUIRED) {
|
|
34
|
+
* // prompt for TOTP code, then call auth.totp.verifySignIn()
|
|
35
|
+
* } else {
|
|
36
|
+
* // user is signed in — store result.access_token if using JWT mode
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
signIn(baseUrl: string, credentials: EmailPasswordCredentials): Promise<SignInResponse>;
|
|
41
|
+
/**
|
|
42
|
+
* Confirms the one-time code sent to the user's email after a sign-in
|
|
43
|
+
* that returned `status === SignInStatus.MFA_REQUIRED`.
|
|
44
|
+
*/
|
|
45
|
+
verifyMfa(baseUrl: string, input: MfaVerifyInput): Promise<GenericSuccessResponse>;
|
|
46
|
+
/**
|
|
47
|
+
* Looks up the username associated with an email address.
|
|
48
|
+
*/
|
|
49
|
+
getUsername(baseUrl: string, email: string): Promise<GenericSuccessResponse>;
|
|
50
|
+
}
|
|
51
|
+
export { SignInStatus };
|
|
52
|
+
//# sourceMappingURL=emailPassword.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailPassword.d.ts","sourceRoot":"","sources":["../../src/methods/emailPassword.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,wBAAwB,EACxB,cAAc,EACd,cAAc,EACd,sBAAsB,EACvB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAiB;IAG5B;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,wBAAwB,GACpC,OAAO,CAAC,sBAAsB,CAAC;IAkBlC;;;;;;;;;;;;;;;;OAgBG;IACG,MAAM,CACV,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,wBAAwB,GACpC,OAAO,CAAC,cAAc,CAAC;IAe1B;;;OAGG;IACG,SAAS,CACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,sBAAsB,CAAC;IAelC;;OAEG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,sBAAsB,CAAC;CASnC;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { MagicLinkResponse, MfaVerifyInput, GenericSuccessResponse } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Email Magic Link authentication.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Call `send(email)` → server emails a one-time code to the user.
|
|
7
|
+
* 2. Response contains a `mfa` session ID.
|
|
8
|
+
* 3. User enters the code; call `verify({ sessionId, code })` to complete sign-in.
|
|
9
|
+
*/
|
|
10
|
+
export declare class MagicLinkAuth {
|
|
11
|
+
/**
|
|
12
|
+
* Sends a magic-link code to the provided email address.
|
|
13
|
+
*
|
|
14
|
+
* @returns A session ID (`mfa` field) that you must pass to `verify()`.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* const { mfa: sessionId } = await auth.magicLink.send(email);
|
|
18
|
+
* // store sessionId, prompt user for code
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
send(baseUrl: string, email: string): Promise<MagicLinkResponse>;
|
|
22
|
+
/**
|
|
23
|
+
* Verifies the code the user received and completes sign-in.
|
|
24
|
+
*/
|
|
25
|
+
verify(baseUrl: string, input: MfaVerifyInput): Promise<GenericSuccessResponse>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=magicLink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"magicLink.d.ts","sourceRoot":"","sources":["../../src/methods/magicLink.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACvB,MAAM,UAAU,CAAC;AAElB;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB;;;;;;;;;OASG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAUtE;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,sBAAsB,CAAC;CAYnC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ResetPasswordInput, ForgotPasswordConfirmInput, ForgotPasswordResponse, GenericSuccessResponse } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Password management methods.
|
|
4
|
+
*
|
|
5
|
+
* ── Reset password (authenticated user) ──────────────────────────────
|
|
6
|
+
* The user knows their current password and wants to change it.
|
|
7
|
+
* Call `reset({ oldPassword, newPassword })`.
|
|
8
|
+
*
|
|
9
|
+
* ── Forgot password (unauthenticated) ────────────────────────────────
|
|
10
|
+
* 1. Call `forgot(email)` → server emails a code and returns a session ID.
|
|
11
|
+
* 2. User enters the code from their email.
|
|
12
|
+
* 3. Call `confirmForgot({ sessionId, code, password })` to set the new password.
|
|
13
|
+
*/
|
|
14
|
+
export declare class PasswordAuth {
|
|
15
|
+
/**
|
|
16
|
+
* Changes the password for an already authenticated user.
|
|
17
|
+
*/
|
|
18
|
+
reset(baseUrl: string, input: ResetPasswordInput): Promise<GenericSuccessResponse>;
|
|
19
|
+
/**
|
|
20
|
+
* Initiates the forgot-password flow by sending a reset code to the
|
|
21
|
+
* user's email address.
|
|
22
|
+
*
|
|
23
|
+
* @returns A session ID (`mfa` field) required by `confirmForgot()`.
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* const { mfa: sessionId } = await auth.password.forgot(email);
|
|
27
|
+
* // prompt user for code
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
forgot(baseUrl: string, email: string): Promise<ForgotPasswordResponse>;
|
|
31
|
+
/**
|
|
32
|
+
* Completes the forgot-password flow by verifying the emailed code
|
|
33
|
+
* and setting the new password.
|
|
34
|
+
*/
|
|
35
|
+
confirmForgot(baseUrl: string, input: ForgotPasswordConfirmInput): Promise<GenericSuccessResponse>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=password.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/methods/password.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAClB,0BAA0B,EAC1B,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;GAWG;AACH,qBAAa,YAAY;IACvB;;OAEG;IACG,KAAK,CACT,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,sBAAsB,CAAC;IAalC;;;;;;;;;;OAUG;IACG,MAAM,CACV,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,sBAAsB,CAAC;IAUlC;;;OAGG;IACG,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,sBAAsB,CAAC;CAanC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AuthUser } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Session-based auth helpers.
|
|
4
|
+
*
|
|
5
|
+
* When the developer chooses sessions over JWTs, the server sets an
|
|
6
|
+
* HttpOnly session cookie. These methods let you read and verify
|
|
7
|
+
* that session without managing tokens yourself.
|
|
8
|
+
*
|
|
9
|
+
* Note: An access token is still returned by the server even in session
|
|
10
|
+
* mode, so you can use it to authenticate with downstream services if needed.
|
|
11
|
+
*/
|
|
12
|
+
export declare class SessionManager {
|
|
13
|
+
/**
|
|
14
|
+
* Fetches the currently authenticated user from the server.
|
|
15
|
+
* Relies on the session cookie being present in the browser.
|
|
16
|
+
*
|
|
17
|
+
* Use this instead of decoding the JWT when you want the
|
|
18
|
+
* authoritative user object from your database.
|
|
19
|
+
*/
|
|
20
|
+
getUser(baseUrl: string): Promise<AuthUser>;
|
|
21
|
+
/**
|
|
22
|
+
* Verifies that a session is still valid for a given email address.
|
|
23
|
+
* Useful for server-side checks or sensitive operations.
|
|
24
|
+
*/
|
|
25
|
+
verifySession(baseUrl: string, email: string): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/methods/session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;;;;;GASG;AACH,qBAAa,cAAc;IAGzB;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAMjD;;;OAGG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMnE"}
|