@reauth-dev/sdk 0.1.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/LICENSE +21 -0
- package/README.md +252 -0
- package/dist/chunk-JX2J36FS.mjs +269 -0
- package/dist/index.d.mts +127 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.js +308 -0
- package/dist/index.mjs +17 -0
- package/dist/react/index.d.mts +123 -0
- package/dist/react/index.d.ts +123 -0
- package/dist/react/index.js +448 -0
- package/dist/react/index.mjs +154 -0
- package/dist/server.d.mts +188 -0
- package/dist/server.d.ts +188 -0
- package/dist/server.js +391 -0
- package/dist/server.mjs +356 -0
- package/dist/types-D8oOYbeC.d.mts +169 -0
- package/dist/types-D8oOYbeC.d.ts +169 -0
- package/dist/webhooks.d.mts +23 -0
- package/dist/webhooks.d.ts +23 -0
- package/dist/webhooks.js +123 -0
- package/dist/webhooks.mjs +94 -0
- package/package.json +78 -0
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
// src/server.ts
|
|
2
|
+
import { hkdf } from "crypto";
|
|
3
|
+
import * as jose from "jose";
|
|
4
|
+
async function deriveJwtSecret(apiKey, domainId) {
|
|
5
|
+
const salt = Buffer.from(domainId.replace(/-/g, ""), "hex");
|
|
6
|
+
const info = Buffer.from("reauth-jwt-v1");
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
hkdf("sha256", apiKey, salt, info, 32, (err, derivedKey) => {
|
|
9
|
+
if (err) reject(err);
|
|
10
|
+
else resolve(Buffer.from(derivedKey).toString("hex"));
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function transformSubscription(sub) {
|
|
15
|
+
return {
|
|
16
|
+
status: sub.status,
|
|
17
|
+
planCode: sub.plan_code,
|
|
18
|
+
planName: sub.plan_name,
|
|
19
|
+
currentPeriodEnd: sub.current_period_end,
|
|
20
|
+
cancelAtPeriodEnd: sub.cancel_at_period_end,
|
|
21
|
+
trialEndsAt: sub.trial_ends_at
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function parseCookies(cookieHeader) {
|
|
25
|
+
const cookies = {};
|
|
26
|
+
for (const cookie of cookieHeader.split(";")) {
|
|
27
|
+
const [key, ...valueParts] = cookie.trim().split("=");
|
|
28
|
+
if (key) {
|
|
29
|
+
try {
|
|
30
|
+
cookies[key] = decodeURIComponent(valueParts.join("="));
|
|
31
|
+
} catch {
|
|
32
|
+
cookies[key] = valueParts.join("=");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return cookies;
|
|
37
|
+
}
|
|
38
|
+
function createServerClient(config) {
|
|
39
|
+
const { domain, apiKey } = config;
|
|
40
|
+
if (!apiKey) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"apiKey is required for createServerClient. Get one from the Reauth dashboard."
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
const developerBaseUrl = `https://reauth.${domain}/api/developer`;
|
|
46
|
+
return {
|
|
47
|
+
/**
|
|
48
|
+
* Verify a JWT token locally using HKDF-derived secret.
|
|
49
|
+
* No network call required - fast and reliable.
|
|
50
|
+
*
|
|
51
|
+
* The domain_id is extracted from the token claims automatically.
|
|
52
|
+
*
|
|
53
|
+
* @param token - The JWT token to verify
|
|
54
|
+
* @returns AuthResult with user info from claims
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const result = await reauth.verifyToken(token);
|
|
59
|
+
* if (result.valid && result.user) {
|
|
60
|
+
* console.log('User ID:', result.user.id);
|
|
61
|
+
* console.log('Roles:', result.user.roles);
|
|
62
|
+
* console.log('Subscription:', result.user.subscription);
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
async verifyToken(token) {
|
|
67
|
+
try {
|
|
68
|
+
const unverified = jose.decodeJwt(token);
|
|
69
|
+
const domainId = unverified.domain_id;
|
|
70
|
+
const unverifiedDomain = unverified.domain;
|
|
71
|
+
if (!domainId) {
|
|
72
|
+
return { valid: false, user: null, claims: null, error: "Missing domain_id in token" };
|
|
73
|
+
}
|
|
74
|
+
if (unverifiedDomain !== domain) {
|
|
75
|
+
return { valid: false, user: null, claims: null, error: "Domain mismatch" };
|
|
76
|
+
}
|
|
77
|
+
const secret = await deriveJwtSecret(apiKey, domainId);
|
|
78
|
+
const { payload } = await jose.jwtVerify(
|
|
79
|
+
token,
|
|
80
|
+
new TextEncoder().encode(secret),
|
|
81
|
+
{
|
|
82
|
+
algorithms: ["HS256"],
|
|
83
|
+
clockTolerance: 60
|
|
84
|
+
// 60 seconds clock skew tolerance
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
const claims = payload;
|
|
88
|
+
if (claims.domain !== domain) {
|
|
89
|
+
return { valid: false, user: null, claims: null, error: "Domain mismatch" };
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
valid: true,
|
|
93
|
+
user: {
|
|
94
|
+
id: claims.sub,
|
|
95
|
+
roles: claims.roles,
|
|
96
|
+
subscription: transformSubscription(claims.subscription)
|
|
97
|
+
},
|
|
98
|
+
claims
|
|
99
|
+
};
|
|
100
|
+
} catch (err) {
|
|
101
|
+
const error = err instanceof Error ? err.message : "Unknown error";
|
|
102
|
+
return { valid: false, user: null, claims: null, error };
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* Extract a token from a request object.
|
|
107
|
+
* Tries Authorization: Bearer header first, then falls back to cookies.
|
|
108
|
+
*
|
|
109
|
+
* @param request - Object with headers (authorization and/or cookie)
|
|
110
|
+
* @returns The token string or null if not found
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const token = reauth.extractToken({
|
|
115
|
+
* headers: {
|
|
116
|
+
* authorization: req.headers.authorization,
|
|
117
|
+
* cookie: req.headers.cookie,
|
|
118
|
+
* },
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
extractToken(request) {
|
|
123
|
+
const authHeader = request.headers?.authorization;
|
|
124
|
+
if (authHeader?.startsWith("Bearer ")) {
|
|
125
|
+
return authHeader.slice(7);
|
|
126
|
+
}
|
|
127
|
+
const cookieHeader = request.headers?.cookie;
|
|
128
|
+
if (cookieHeader) {
|
|
129
|
+
const cookies = parseCookies(cookieHeader);
|
|
130
|
+
if (cookies["end_user_access_token"]) {
|
|
131
|
+
return cookies["end_user_access_token"];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* Authenticate a request by extracting and verifying the token.
|
|
138
|
+
* This is a convenience method combining extractToken and verifyToken.
|
|
139
|
+
*
|
|
140
|
+
* @param request - Object with headers (authorization and/or cookie)
|
|
141
|
+
* @returns AuthResult with user info from claims
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* // Express/Node.js
|
|
146
|
+
* async function authMiddleware(req, res, next) {
|
|
147
|
+
* const result = await reauth.authenticate({
|
|
148
|
+
* headers: {
|
|
149
|
+
* authorization: req.headers.authorization,
|
|
150
|
+
* cookie: req.headers.cookie,
|
|
151
|
+
* },
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* if (!result.valid || !result.user) {
|
|
155
|
+
* res.status(401).json({ error: result.error || 'Unauthorized' });
|
|
156
|
+
* return;
|
|
157
|
+
* }
|
|
158
|
+
*
|
|
159
|
+
* req.user = result.user;
|
|
160
|
+
* next();
|
|
161
|
+
* }
|
|
162
|
+
*
|
|
163
|
+
* // Next.js App Router
|
|
164
|
+
* export async function GET(request: NextRequest) {
|
|
165
|
+
* const result = await reauth.authenticate({
|
|
166
|
+
* headers: {
|
|
167
|
+
* authorization: request.headers.get('authorization') ?? undefined,
|
|
168
|
+
* cookie: request.headers.get('cookie') ?? undefined,
|
|
169
|
+
* },
|
|
170
|
+
* });
|
|
171
|
+
*
|
|
172
|
+
* if (!result.valid) {
|
|
173
|
+
* return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
174
|
+
* }
|
|
175
|
+
*
|
|
176
|
+
* return NextResponse.json({ user: result.user });
|
|
177
|
+
* }
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
async authenticate(request) {
|
|
181
|
+
const token = this.extractToken(request);
|
|
182
|
+
if (!token) {
|
|
183
|
+
return { valid: false, user: null, claims: null, error: "No token provided" };
|
|
184
|
+
}
|
|
185
|
+
return this.verifyToken(token);
|
|
186
|
+
},
|
|
187
|
+
/**
|
|
188
|
+
* Get user details by ID from the backend.
|
|
189
|
+
* Use this when you need full user info like email, frozen status, etc.
|
|
190
|
+
* that isn't available in the JWT claims.
|
|
191
|
+
*
|
|
192
|
+
* @param userId - The user ID to fetch
|
|
193
|
+
* @returns UserDetails or null if not found
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* // After verifying token, fetch full user details if needed
|
|
198
|
+
* const result = await reauth.authenticate(request);
|
|
199
|
+
* if (result.valid && result.user) {
|
|
200
|
+
* // If you need email or other details not in JWT
|
|
201
|
+
* const details = await reauth.getUserById(result.user.id);
|
|
202
|
+
* if (details) {
|
|
203
|
+
* console.log('Email:', details.email);
|
|
204
|
+
* console.log('Frozen:', details.isFrozen);
|
|
205
|
+
* }
|
|
206
|
+
* }
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
async getUserById(userId) {
|
|
210
|
+
const res = await fetch(`${developerBaseUrl}/users/${userId}`, {
|
|
211
|
+
headers: {
|
|
212
|
+
Authorization: `Bearer ${apiKey}`
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
if (!res.ok) {
|
|
216
|
+
if (res.status === 401) {
|
|
217
|
+
throw new Error("Invalid API key");
|
|
218
|
+
}
|
|
219
|
+
if (res.status === 404) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
throw new Error(`Failed to get user: ${res.status}`);
|
|
223
|
+
}
|
|
224
|
+
const data = await res.json();
|
|
225
|
+
return {
|
|
226
|
+
id: data.id,
|
|
227
|
+
email: data.email,
|
|
228
|
+
roles: data.roles,
|
|
229
|
+
emailVerifiedAt: data.email_verified_at,
|
|
230
|
+
lastLoginAt: data.last_login_at,
|
|
231
|
+
isFrozen: data.is_frozen,
|
|
232
|
+
isWhitelisted: data.is_whitelisted,
|
|
233
|
+
createdAt: data.created_at
|
|
234
|
+
};
|
|
235
|
+
},
|
|
236
|
+
// ========================================================================
|
|
237
|
+
// Balance Methods
|
|
238
|
+
// ========================================================================
|
|
239
|
+
/**
|
|
240
|
+
* Get a user's current balance.
|
|
241
|
+
*
|
|
242
|
+
* @param userId - The user ID to check
|
|
243
|
+
* @returns Object with the current balance
|
|
244
|
+
*/
|
|
245
|
+
async getBalance(userId) {
|
|
246
|
+
const res = await fetch(`${developerBaseUrl}/users/${userId}/balance`, {
|
|
247
|
+
headers: {
|
|
248
|
+
Authorization: `Bearer ${apiKey}`
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
if (!res.ok) {
|
|
252
|
+
if (res.status === 401) throw new Error("Invalid API key");
|
|
253
|
+
throw new Error(`Failed to get balance: ${res.status}`);
|
|
254
|
+
}
|
|
255
|
+
return res.json();
|
|
256
|
+
},
|
|
257
|
+
/**
|
|
258
|
+
* Charge (deduct) credits from a user's balance.
|
|
259
|
+
*
|
|
260
|
+
* @param userId - The user ID to charge
|
|
261
|
+
* @param opts - Charge options (amount, requestUuid for idempotency, optional note)
|
|
262
|
+
* @returns Object with the new balance after charge
|
|
263
|
+
* @throws Error with status 402 if insufficient balance, 400 if invalid amount
|
|
264
|
+
*/
|
|
265
|
+
async charge(userId, opts) {
|
|
266
|
+
const res = await fetch(`${developerBaseUrl}/users/${userId}/charge`, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: {
|
|
269
|
+
"Content-Type": "application/json",
|
|
270
|
+
Authorization: `Bearer ${apiKey}`
|
|
271
|
+
},
|
|
272
|
+
body: JSON.stringify({
|
|
273
|
+
amount: opts.amount,
|
|
274
|
+
request_uuid: opts.requestUuid,
|
|
275
|
+
note: opts.note
|
|
276
|
+
})
|
|
277
|
+
});
|
|
278
|
+
if (!res.ok) {
|
|
279
|
+
if (res.status === 401) throw new Error("Invalid API key");
|
|
280
|
+
if (res.status === 402) throw new Error("Insufficient balance");
|
|
281
|
+
if (res.status === 400) throw new Error("Invalid amount");
|
|
282
|
+
throw new Error(`Failed to charge balance: ${res.status}`);
|
|
283
|
+
}
|
|
284
|
+
const data = await res.json();
|
|
285
|
+
return { newBalance: data.new_balance };
|
|
286
|
+
},
|
|
287
|
+
/**
|
|
288
|
+
* Deposit (add) credits to a user's balance.
|
|
289
|
+
*
|
|
290
|
+
* @param userId - The user ID to deposit to
|
|
291
|
+
* @param opts - Deposit options (amount, requestUuid for idempotency, optional note)
|
|
292
|
+
* @returns Object with the new balance after deposit
|
|
293
|
+
*/
|
|
294
|
+
async deposit(userId, opts) {
|
|
295
|
+
const res = await fetch(`${developerBaseUrl}/users/${userId}/deposit`, {
|
|
296
|
+
method: "POST",
|
|
297
|
+
headers: {
|
|
298
|
+
"Content-Type": "application/json",
|
|
299
|
+
Authorization: `Bearer ${apiKey}`
|
|
300
|
+
},
|
|
301
|
+
body: JSON.stringify({
|
|
302
|
+
amount: opts.amount,
|
|
303
|
+
request_uuid: opts.requestUuid,
|
|
304
|
+
note: opts.note
|
|
305
|
+
})
|
|
306
|
+
});
|
|
307
|
+
if (!res.ok) {
|
|
308
|
+
if (res.status === 401) throw new Error("Invalid API key");
|
|
309
|
+
if (res.status === 400) throw new Error("Invalid amount");
|
|
310
|
+
throw new Error(`Failed to deposit balance: ${res.status}`);
|
|
311
|
+
}
|
|
312
|
+
const data = await res.json();
|
|
313
|
+
return { newBalance: data.new_balance };
|
|
314
|
+
},
|
|
315
|
+
/**
|
|
316
|
+
* Get a user's balance transaction history.
|
|
317
|
+
*
|
|
318
|
+
* @param userId - The user ID to get transactions for
|
|
319
|
+
* @param opts - Optional pagination (limit, offset)
|
|
320
|
+
* @returns Object with array of transactions (newest first)
|
|
321
|
+
*/
|
|
322
|
+
async getTransactions(userId, opts) {
|
|
323
|
+
const params = new URLSearchParams();
|
|
324
|
+
if (opts?.limit !== void 0) params.set("limit", String(opts.limit));
|
|
325
|
+
if (opts?.offset !== void 0) params.set("offset", String(opts.offset));
|
|
326
|
+
const qs = params.toString();
|
|
327
|
+
const res = await fetch(
|
|
328
|
+
`${developerBaseUrl}/users/${userId}/balance/transactions${qs ? `?${qs}` : ""}`,
|
|
329
|
+
{
|
|
330
|
+
headers: {
|
|
331
|
+
Authorization: `Bearer ${apiKey}`
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
if (!res.ok) {
|
|
336
|
+
if (res.status === 401) throw new Error("Invalid API key");
|
|
337
|
+
throw new Error(`Failed to get transactions: ${res.status}`);
|
|
338
|
+
}
|
|
339
|
+
const data = await res.json();
|
|
340
|
+
return {
|
|
341
|
+
transactions: data.transactions.map(
|
|
342
|
+
(t) => ({
|
|
343
|
+
id: t.id,
|
|
344
|
+
amountDelta: t.amount_delta,
|
|
345
|
+
reason: t.reason,
|
|
346
|
+
balanceAfter: t.balance_after,
|
|
347
|
+
createdAt: t.created_at
|
|
348
|
+
})
|
|
349
|
+
)
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
export {
|
|
355
|
+
createServerClient
|
|
356
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/** Response from GET /api/public/auth/session */
|
|
2
|
+
type ReauthSession = {
|
|
3
|
+
valid: boolean;
|
|
4
|
+
end_user_id: string | null;
|
|
5
|
+
email: string | null;
|
|
6
|
+
roles: string[] | null;
|
|
7
|
+
waitlist_position: number | null;
|
|
8
|
+
error: string | null;
|
|
9
|
+
error_code: "ACCOUNT_SUSPENDED" | null;
|
|
10
|
+
/** Subscription information (if billing is configured) */
|
|
11
|
+
subscription?: {
|
|
12
|
+
status: string;
|
|
13
|
+
plan_code: string | null;
|
|
14
|
+
plan_name: string | null;
|
|
15
|
+
current_period_end: number | null;
|
|
16
|
+
cancel_at_period_end: boolean | null;
|
|
17
|
+
trial_ends_at: number | null;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/** Authenticated user object (basic) */
|
|
21
|
+
type User = {
|
|
22
|
+
id: string;
|
|
23
|
+
email: string;
|
|
24
|
+
roles: string[];
|
|
25
|
+
};
|
|
26
|
+
/** Full user details (from Developer API) */
|
|
27
|
+
type UserDetails = {
|
|
28
|
+
id: string;
|
|
29
|
+
email: string;
|
|
30
|
+
roles: string[];
|
|
31
|
+
emailVerifiedAt: string | null;
|
|
32
|
+
lastLoginAt: string | null;
|
|
33
|
+
isFrozen: boolean;
|
|
34
|
+
isWhitelisted: boolean;
|
|
35
|
+
createdAt: string | null;
|
|
36
|
+
};
|
|
37
|
+
/** JWT claims for domain end-user tokens */
|
|
38
|
+
type DomainEndUserClaims = {
|
|
39
|
+
/** User ID (subject) */
|
|
40
|
+
sub: string;
|
|
41
|
+
/** Domain ID */
|
|
42
|
+
domain_id: string;
|
|
43
|
+
/** Root domain (e.g., "example.com") */
|
|
44
|
+
domain: string;
|
|
45
|
+
/** User roles */
|
|
46
|
+
roles: string[];
|
|
47
|
+
/** Subscription information */
|
|
48
|
+
subscription: {
|
|
49
|
+
status: string;
|
|
50
|
+
plan_code: string | null;
|
|
51
|
+
plan_name: string | null;
|
|
52
|
+
current_period_end: number | null;
|
|
53
|
+
cancel_at_period_end: boolean | null;
|
|
54
|
+
trial_ends_at: number | null;
|
|
55
|
+
};
|
|
56
|
+
/** Token expiration (Unix timestamp) */
|
|
57
|
+
exp: number;
|
|
58
|
+
/** Token issued at (Unix timestamp) */
|
|
59
|
+
iat: number;
|
|
60
|
+
};
|
|
61
|
+
/** Configuration for browser-side reauth client */
|
|
62
|
+
type ReauthConfig = {
|
|
63
|
+
/** Your verified domain (e.g., "yourdomain.com") */
|
|
64
|
+
domain: string;
|
|
65
|
+
};
|
|
66
|
+
/** Configuration for server-side reauth client */
|
|
67
|
+
type ReauthServerConfig = ReauthConfig & {
|
|
68
|
+
/** API key for server-to-server authentication (required, e.g., "sk_live_...") */
|
|
69
|
+
apiKey: string;
|
|
70
|
+
};
|
|
71
|
+
/** Subscription status values */
|
|
72
|
+
type SubscriptionStatus = "active" | "past_due" | "canceled" | "trialing" | "incomplete" | "incomplete_expired" | "unpaid" | "paused" | "none";
|
|
73
|
+
/** Subscription info included in JWT claims */
|
|
74
|
+
type SubscriptionInfo = {
|
|
75
|
+
/** Current subscription status */
|
|
76
|
+
status: SubscriptionStatus;
|
|
77
|
+
/** Machine-readable plan identifier (e.g., "pro") */
|
|
78
|
+
planCode: string | null;
|
|
79
|
+
/** Human-readable plan name (e.g., "Pro Plan") */
|
|
80
|
+
planName: string | null;
|
|
81
|
+
/** Unix timestamp when current period ends */
|
|
82
|
+
currentPeriodEnd: number | null;
|
|
83
|
+
/** Whether subscription will cancel at period end */
|
|
84
|
+
cancelAtPeriodEnd: boolean | null;
|
|
85
|
+
/** Unix timestamp when trial ends (if applicable) */
|
|
86
|
+
trialEndsAt: number | null;
|
|
87
|
+
};
|
|
88
|
+
/** Authentication result from verifyToken/authenticate */
|
|
89
|
+
type AuthResult = {
|
|
90
|
+
valid: boolean;
|
|
91
|
+
user: {
|
|
92
|
+
id: string;
|
|
93
|
+
roles: string[];
|
|
94
|
+
subscription: SubscriptionInfo;
|
|
95
|
+
} | null;
|
|
96
|
+
claims: DomainEndUserClaims | null;
|
|
97
|
+
error?: string;
|
|
98
|
+
};
|
|
99
|
+
/** Request-like object for extractToken/authenticate */
|
|
100
|
+
type RequestLike = {
|
|
101
|
+
headers?: {
|
|
102
|
+
authorization?: string;
|
|
103
|
+
cookie?: string;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
/** Response from GET /auth/token endpoint */
|
|
107
|
+
type TokenResponse = {
|
|
108
|
+
/** The JWT access token */
|
|
109
|
+
accessToken: string;
|
|
110
|
+
/** Token expiration time in seconds */
|
|
111
|
+
expiresIn: number;
|
|
112
|
+
/** Token type (always "Bearer") */
|
|
113
|
+
tokenType: string;
|
|
114
|
+
};
|
|
115
|
+
/** Subscription plan available for purchase */
|
|
116
|
+
type SubscriptionPlan = {
|
|
117
|
+
id: string;
|
|
118
|
+
code: string;
|
|
119
|
+
name: string;
|
|
120
|
+
description: string | null;
|
|
121
|
+
priceCents: number;
|
|
122
|
+
currency: string;
|
|
123
|
+
interval: "monthly" | "yearly" | "custom";
|
|
124
|
+
intervalCount: number;
|
|
125
|
+
trialDays: number;
|
|
126
|
+
features: string[];
|
|
127
|
+
displayOrder: number;
|
|
128
|
+
};
|
|
129
|
+
/** User's current subscription details */
|
|
130
|
+
type UserSubscription = {
|
|
131
|
+
id: string | null;
|
|
132
|
+
planCode: string | null;
|
|
133
|
+
planName: string | null;
|
|
134
|
+
status: SubscriptionStatus;
|
|
135
|
+
currentPeriodEnd: number | null;
|
|
136
|
+
trialEnd: number | null;
|
|
137
|
+
cancelAtPeriodEnd: boolean | null;
|
|
138
|
+
};
|
|
139
|
+
/** Checkout session response */
|
|
140
|
+
type CheckoutSession = {
|
|
141
|
+
checkoutUrl: string;
|
|
142
|
+
};
|
|
143
|
+
/** A single balance transaction record */
|
|
144
|
+
type BalanceTransaction = {
|
|
145
|
+
id: string;
|
|
146
|
+
amountDelta: number;
|
|
147
|
+
reason: Record<string, unknown>;
|
|
148
|
+
balanceAfter: number;
|
|
149
|
+
createdAt: string;
|
|
150
|
+
};
|
|
151
|
+
/** Options for charging a user's balance */
|
|
152
|
+
type ChargeOptions = {
|
|
153
|
+
amount: number;
|
|
154
|
+
requestUuid: string;
|
|
155
|
+
note?: string;
|
|
156
|
+
};
|
|
157
|
+
/** Options for depositing to a user's balance */
|
|
158
|
+
type DepositOptions = {
|
|
159
|
+
amount: number;
|
|
160
|
+
requestUuid: string;
|
|
161
|
+
note?: string;
|
|
162
|
+
};
|
|
163
|
+
/** Pagination options for transaction queries */
|
|
164
|
+
type TransactionsPaginationOptions = {
|
|
165
|
+
limit?: number;
|
|
166
|
+
offset?: number;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export type { AuthResult as A, BalanceTransaction as B, CheckoutSession as C, DomainEndUserClaims as D, ReauthConfig as R, SubscriptionPlan as S, TokenResponse as T, UserSubscription as U, ReauthSession as a, TransactionsPaginationOptions as b, User as c, UserDetails as d, ReauthServerConfig as e, RequestLike as f, SubscriptionInfo as g, ChargeOptions as h, DepositOptions as i };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/** Response from GET /api/public/auth/session */
|
|
2
|
+
type ReauthSession = {
|
|
3
|
+
valid: boolean;
|
|
4
|
+
end_user_id: string | null;
|
|
5
|
+
email: string | null;
|
|
6
|
+
roles: string[] | null;
|
|
7
|
+
waitlist_position: number | null;
|
|
8
|
+
error: string | null;
|
|
9
|
+
error_code: "ACCOUNT_SUSPENDED" | null;
|
|
10
|
+
/** Subscription information (if billing is configured) */
|
|
11
|
+
subscription?: {
|
|
12
|
+
status: string;
|
|
13
|
+
plan_code: string | null;
|
|
14
|
+
plan_name: string | null;
|
|
15
|
+
current_period_end: number | null;
|
|
16
|
+
cancel_at_period_end: boolean | null;
|
|
17
|
+
trial_ends_at: number | null;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/** Authenticated user object (basic) */
|
|
21
|
+
type User = {
|
|
22
|
+
id: string;
|
|
23
|
+
email: string;
|
|
24
|
+
roles: string[];
|
|
25
|
+
};
|
|
26
|
+
/** Full user details (from Developer API) */
|
|
27
|
+
type UserDetails = {
|
|
28
|
+
id: string;
|
|
29
|
+
email: string;
|
|
30
|
+
roles: string[];
|
|
31
|
+
emailVerifiedAt: string | null;
|
|
32
|
+
lastLoginAt: string | null;
|
|
33
|
+
isFrozen: boolean;
|
|
34
|
+
isWhitelisted: boolean;
|
|
35
|
+
createdAt: string | null;
|
|
36
|
+
};
|
|
37
|
+
/** JWT claims for domain end-user tokens */
|
|
38
|
+
type DomainEndUserClaims = {
|
|
39
|
+
/** User ID (subject) */
|
|
40
|
+
sub: string;
|
|
41
|
+
/** Domain ID */
|
|
42
|
+
domain_id: string;
|
|
43
|
+
/** Root domain (e.g., "example.com") */
|
|
44
|
+
domain: string;
|
|
45
|
+
/** User roles */
|
|
46
|
+
roles: string[];
|
|
47
|
+
/** Subscription information */
|
|
48
|
+
subscription: {
|
|
49
|
+
status: string;
|
|
50
|
+
plan_code: string | null;
|
|
51
|
+
plan_name: string | null;
|
|
52
|
+
current_period_end: number | null;
|
|
53
|
+
cancel_at_period_end: boolean | null;
|
|
54
|
+
trial_ends_at: number | null;
|
|
55
|
+
};
|
|
56
|
+
/** Token expiration (Unix timestamp) */
|
|
57
|
+
exp: number;
|
|
58
|
+
/** Token issued at (Unix timestamp) */
|
|
59
|
+
iat: number;
|
|
60
|
+
};
|
|
61
|
+
/** Configuration for browser-side reauth client */
|
|
62
|
+
type ReauthConfig = {
|
|
63
|
+
/** Your verified domain (e.g., "yourdomain.com") */
|
|
64
|
+
domain: string;
|
|
65
|
+
};
|
|
66
|
+
/** Configuration for server-side reauth client */
|
|
67
|
+
type ReauthServerConfig = ReauthConfig & {
|
|
68
|
+
/** API key for server-to-server authentication (required, e.g., "sk_live_...") */
|
|
69
|
+
apiKey: string;
|
|
70
|
+
};
|
|
71
|
+
/** Subscription status values */
|
|
72
|
+
type SubscriptionStatus = "active" | "past_due" | "canceled" | "trialing" | "incomplete" | "incomplete_expired" | "unpaid" | "paused" | "none";
|
|
73
|
+
/** Subscription info included in JWT claims */
|
|
74
|
+
type SubscriptionInfo = {
|
|
75
|
+
/** Current subscription status */
|
|
76
|
+
status: SubscriptionStatus;
|
|
77
|
+
/** Machine-readable plan identifier (e.g., "pro") */
|
|
78
|
+
planCode: string | null;
|
|
79
|
+
/** Human-readable plan name (e.g., "Pro Plan") */
|
|
80
|
+
planName: string | null;
|
|
81
|
+
/** Unix timestamp when current period ends */
|
|
82
|
+
currentPeriodEnd: number | null;
|
|
83
|
+
/** Whether subscription will cancel at period end */
|
|
84
|
+
cancelAtPeriodEnd: boolean | null;
|
|
85
|
+
/** Unix timestamp when trial ends (if applicable) */
|
|
86
|
+
trialEndsAt: number | null;
|
|
87
|
+
};
|
|
88
|
+
/** Authentication result from verifyToken/authenticate */
|
|
89
|
+
type AuthResult = {
|
|
90
|
+
valid: boolean;
|
|
91
|
+
user: {
|
|
92
|
+
id: string;
|
|
93
|
+
roles: string[];
|
|
94
|
+
subscription: SubscriptionInfo;
|
|
95
|
+
} | null;
|
|
96
|
+
claims: DomainEndUserClaims | null;
|
|
97
|
+
error?: string;
|
|
98
|
+
};
|
|
99
|
+
/** Request-like object for extractToken/authenticate */
|
|
100
|
+
type RequestLike = {
|
|
101
|
+
headers?: {
|
|
102
|
+
authorization?: string;
|
|
103
|
+
cookie?: string;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
/** Response from GET /auth/token endpoint */
|
|
107
|
+
type TokenResponse = {
|
|
108
|
+
/** The JWT access token */
|
|
109
|
+
accessToken: string;
|
|
110
|
+
/** Token expiration time in seconds */
|
|
111
|
+
expiresIn: number;
|
|
112
|
+
/** Token type (always "Bearer") */
|
|
113
|
+
tokenType: string;
|
|
114
|
+
};
|
|
115
|
+
/** Subscription plan available for purchase */
|
|
116
|
+
type SubscriptionPlan = {
|
|
117
|
+
id: string;
|
|
118
|
+
code: string;
|
|
119
|
+
name: string;
|
|
120
|
+
description: string | null;
|
|
121
|
+
priceCents: number;
|
|
122
|
+
currency: string;
|
|
123
|
+
interval: "monthly" | "yearly" | "custom";
|
|
124
|
+
intervalCount: number;
|
|
125
|
+
trialDays: number;
|
|
126
|
+
features: string[];
|
|
127
|
+
displayOrder: number;
|
|
128
|
+
};
|
|
129
|
+
/** User's current subscription details */
|
|
130
|
+
type UserSubscription = {
|
|
131
|
+
id: string | null;
|
|
132
|
+
planCode: string | null;
|
|
133
|
+
planName: string | null;
|
|
134
|
+
status: SubscriptionStatus;
|
|
135
|
+
currentPeriodEnd: number | null;
|
|
136
|
+
trialEnd: number | null;
|
|
137
|
+
cancelAtPeriodEnd: boolean | null;
|
|
138
|
+
};
|
|
139
|
+
/** Checkout session response */
|
|
140
|
+
type CheckoutSession = {
|
|
141
|
+
checkoutUrl: string;
|
|
142
|
+
};
|
|
143
|
+
/** A single balance transaction record */
|
|
144
|
+
type BalanceTransaction = {
|
|
145
|
+
id: string;
|
|
146
|
+
amountDelta: number;
|
|
147
|
+
reason: Record<string, unknown>;
|
|
148
|
+
balanceAfter: number;
|
|
149
|
+
createdAt: string;
|
|
150
|
+
};
|
|
151
|
+
/** Options for charging a user's balance */
|
|
152
|
+
type ChargeOptions = {
|
|
153
|
+
amount: number;
|
|
154
|
+
requestUuid: string;
|
|
155
|
+
note?: string;
|
|
156
|
+
};
|
|
157
|
+
/** Options for depositing to a user's balance */
|
|
158
|
+
type DepositOptions = {
|
|
159
|
+
amount: number;
|
|
160
|
+
requestUuid: string;
|
|
161
|
+
note?: string;
|
|
162
|
+
};
|
|
163
|
+
/** Pagination options for transaction queries */
|
|
164
|
+
type TransactionsPaginationOptions = {
|
|
165
|
+
limit?: number;
|
|
166
|
+
offset?: number;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export type { AuthResult as A, BalanceTransaction as B, CheckoutSession as C, DomainEndUserClaims as D, ReauthConfig as R, SubscriptionPlan as S, TokenResponse as T, UserSubscription as U, ReauthSession as a, TransactionsPaginationOptions as b, User as c, UserDetails as d, ReauthServerConfig as e, RequestLike as f, SubscriptionInfo as g, ChargeOptions as h, DepositOptions as i };
|