@atlasauth/backend 0.22.0 → 0.24.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/CHANGELOG.md +18 -0
- package/dist/auth0-session.d.ts +23 -0
- package/dist/auth0-session.js +80 -0
- package/dist/auth0-session.js.map +1 -0
- package/dist/better-auth.d.ts +4 -8
- package/dist/better-auth.js +42 -150
- package/dist/better-auth.js.map +1 -1
- package/dist/client/index.d.ts +67 -3
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/instance.d.ts +61 -1
- package/dist/client/instance.js +8 -0
- package/dist/client/instance.js.map +1 -1
- package/dist/client/jwt-templates.d.ts +29 -4
- package/dist/client/jwt-templates.js +1 -1
- package/dist/client/jwt-templates.js.map +1 -1
- package/dist/client/migrations.d.ts +286 -0
- package/dist/client/migrations.js +103 -0
- package/dist/client/migrations.js.map +1 -0
- package/dist/client/operator.d.ts +35 -0
- package/dist/client/operator.js +47 -12
- package/dist/client/operator.js.map +1 -1
- package/dist/framework-bridge.d.ts +98 -0
- package/dist/framework-bridge.js +264 -0
- package/dist/framework-bridge.js.map +1 -0
- package/dist/framework-sessions.d.ts +147 -0
- package/dist/framework-sessions.js +544 -0
- package/dist/framework-sessions.js.map +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/legacy-issuer-presets.d.ts +85 -0
- package/dist/legacy-issuer-presets.js +165 -0
- package/dist/legacy-issuer-presets.js.map +1 -0
- package/dist/legacy-issuers.d.ts +16 -2
- package/dist/legacy-issuers.js +16 -1
- package/dist/legacy-issuers.js.map +1 -1
- package/dist/legacy-verify.d.ts +103 -0
- package/dist/legacy-verify.js +244 -0
- package/dist/legacy-verify.js.map +1 -0
- package/dist/migration-bridge.d.ts +153 -0
- package/dist/migration-bridge.js +328 -0
- package/dist/migration-bridge.js.map +1 -0
- package/dist/migration-presets.d.ts +150 -0
- package/dist/migration-presets.js +440 -0
- package/dist/migration-presets.js.map +1 -0
- package/dist/recent-auth.d.ts +21 -0
- package/dist/recent-auth.js +30 -0
- package/dist/recent-auth.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.migrationExchangePath = migrationExchangePath;
|
|
4
|
+
exports.migrationBapiExchangePath = migrationBapiExchangePath;
|
|
5
|
+
exports.exchangeMigrationSession = exchangeMigrationSession;
|
|
6
|
+
exports.parseCookieHeader = parseCookieHeader;
|
|
7
|
+
exports.readSupabaseAccessToken = readSupabaseAccessToken;
|
|
8
|
+
exports.bridgeCookieConfig = bridgeCookieConfig;
|
|
9
|
+
exports.createMigrationBridge = createMigrationBridge;
|
|
10
|
+
const migration_presets_1 = require("./migration-presets");
|
|
11
|
+
/**
|
|
12
|
+
* Moving to Atlas from ANY auth vendor without signing anyone out — the
|
|
13
|
+
* vendor-neutral zero-logout bridge (Better Auth's `betterAuthBridge` is now an
|
|
14
|
+
* alias of this with `source: 'better_auth'`).
|
|
15
|
+
*
|
|
16
|
+
* During the migration window a returning user still carries the old vendor's
|
|
17
|
+
* session cookie (or bearer token). The bridge reads it, exchanges it ONCE with
|
|
18
|
+
* Atlas (`POST /v1/migrations/{source}/exchange` with the secret key, or the
|
|
19
|
+
* Frontend API twin `POST /v1/client/migrations/{source}/exchange`), sets the
|
|
20
|
+
* Atlas session as your own first-party cookies and clears the old ones. Atlas
|
|
21
|
+
* verifies the old token (a JWT against the vendor's keys, or an opaque token
|
|
22
|
+
* against the sessions you imported) and runs the normal sign-in path on it —
|
|
23
|
+
* MFA policy included.
|
|
24
|
+
*
|
|
25
|
+
* Framework-neutral: {@link createMigrationBridge} returns a decision with the
|
|
26
|
+
* cookies to set and clear; the Next.js middleware and the Express / Fastify /
|
|
27
|
+
* Hono adapters render it (`migrationBridge({ source })`).
|
|
28
|
+
*/
|
|
29
|
+
/** Default Backend API origin. */
|
|
30
|
+
const DEFAULT_BAPI_URL = 'https://api.atlasauth.net';
|
|
31
|
+
/** The Frontend API exchange path for a source. */
|
|
32
|
+
function migrationExchangePath(source) {
|
|
33
|
+
return `/v1/client/migrations/${encodeURIComponent(source)}/exchange`;
|
|
34
|
+
}
|
|
35
|
+
/** The Backend API (secret-key) exchange path for a source. */
|
|
36
|
+
function migrationBapiExchangePath(source) {
|
|
37
|
+
return `/v1/migrations/${encodeURIComponent(source)}/exchange`;
|
|
38
|
+
}
|
|
39
|
+
const KNOWN_REFUSALS = ['closed', 'invalid', 'signature_invalid', 'expired', 'reused', 'user_unavailable', 'user_unknown', 'rate_limited'];
|
|
40
|
+
/**
|
|
41
|
+
* Exchange an old vendor session for an Atlas session, server to server
|
|
42
|
+
* (`delivery: "body"`). Never throws: a transport failure is
|
|
43
|
+
* `{ kind: 'refused', outcome: 'unavailable' }`, so the caller keeps the old
|
|
44
|
+
* cookie and tries again on a later request.
|
|
45
|
+
*/
|
|
46
|
+
async function exchangeMigrationSession(options) {
|
|
47
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
48
|
+
const viaSecretKey = Boolean(options.secretKey);
|
|
49
|
+
const url = viaSecretKey
|
|
50
|
+
? `${(options.bapiBaseUrl ?? DEFAULT_BAPI_URL).replace(/\/+$/, '')}${migrationBapiExchangePath(options.source)}`
|
|
51
|
+
: new URL(migrationExchangePath(options.source), options.fapiOrigin).toString();
|
|
52
|
+
const headers = { 'content-type': 'application/json' };
|
|
53
|
+
if (viaSecretKey) {
|
|
54
|
+
headers.authorization = `Bearer ${options.secretKey}`;
|
|
55
|
+
if (options.clientIp)
|
|
56
|
+
headers['x-atlas-client-ip'] = options.clientIp;
|
|
57
|
+
if (options.userAgent)
|
|
58
|
+
headers['x-atlas-client-user-agent'] = options.userAgent;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
headers['x-publishable-key'] = options.publishableKey;
|
|
62
|
+
if (options.userAgent)
|
|
63
|
+
headers['user-agent'] = options.userAgent;
|
|
64
|
+
}
|
|
65
|
+
let res;
|
|
66
|
+
try {
|
|
67
|
+
res = await doFetch(url, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers,
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
token: options.token,
|
|
72
|
+
...(viaSecretKey ? {} : { delivery: 'body' }),
|
|
73
|
+
...(options.remember === false ? { remember: false } : {}),
|
|
74
|
+
}),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return { kind: 'refused', outcome: 'unavailable', status: 0 };
|
|
79
|
+
}
|
|
80
|
+
const data = (await res.json().catch(() => null));
|
|
81
|
+
if (res.ok && data?.object === 'session_tokens' && data.jwt && data.refresh_token) {
|
|
82
|
+
return { kind: 'session', jwt: data.jwt, refreshToken: data.refresh_token, sessionId: data.session_id ?? '', userId: data.user_id ?? '', expiresIn: data.expires_in ?? 0 };
|
|
83
|
+
}
|
|
84
|
+
if (res.ok && data?.object === 'sign_in_attempt' && data.id && (data.status === 'needs_second_factor' || data.status === 'needs_mfa_enrollment')) {
|
|
85
|
+
return { kind: 'needs_mfa', attemptId: data.id, status: data.status };
|
|
86
|
+
}
|
|
87
|
+
if (res.status === 429)
|
|
88
|
+
return { kind: 'refused', outcome: 'rate_limited', status: 429 };
|
|
89
|
+
const outcome = data?.errors?.[0]?.meta?.bridge_outcome;
|
|
90
|
+
if (outcome && KNOWN_REFUSALS.includes(outcome))
|
|
91
|
+
return { kind: 'refused', outcome: outcome, status: res.status };
|
|
92
|
+
// Anything else (a 5xx, a guard refusal, an unparsable body) is not a verdict on the old session: keep it.
|
|
93
|
+
return { kind: 'refused', outcome: 'unavailable', status: res.status };
|
|
94
|
+
}
|
|
95
|
+
/** Refusals that say the old session will never exchange: its cookies are cleared. */
|
|
96
|
+
const FINAL = ['invalid', 'signature_invalid', 'expired', 'reused', 'user_unavailable', 'user_unknown'];
|
|
97
|
+
function header(headers, name) {
|
|
98
|
+
if (typeof headers.get === 'function')
|
|
99
|
+
return headers.get(name) ?? undefined;
|
|
100
|
+
const record = headers;
|
|
101
|
+
const value = record[name] ?? record[name.toLowerCase()];
|
|
102
|
+
return Array.isArray(value) ? value.join('; ') : value;
|
|
103
|
+
}
|
|
104
|
+
/** Parse a Cookie header into name → raw value (first occurrence wins). */
|
|
105
|
+
function parseCookieHeader(cookieHeader) {
|
|
106
|
+
const out = {};
|
|
107
|
+
if (!cookieHeader)
|
|
108
|
+
return out;
|
|
109
|
+
for (const part of cookieHeader.split(';')) {
|
|
110
|
+
const i = part.indexOf('=');
|
|
111
|
+
if (i <= 0)
|
|
112
|
+
continue;
|
|
113
|
+
const name = part.slice(0, i).trim();
|
|
114
|
+
if (name && !(name in out))
|
|
115
|
+
out[name] = part.slice(i + 1).trim();
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
/** The unverified `iss` of a compact JWT (routing only; Atlas verifies). */
|
|
120
|
+
function peekIss(token) {
|
|
121
|
+
const parts = token.split('.');
|
|
122
|
+
if (parts.length !== 3)
|
|
123
|
+
return undefined;
|
|
124
|
+
try {
|
|
125
|
+
const json = JSON.parse(decodeBase64Url(parts[1]));
|
|
126
|
+
return typeof json.iss === 'string' ? json.iss : undefined;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function decodeBase64Url(s) {
|
|
133
|
+
const b64 = s.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(s.length / 4) * 4, '=');
|
|
134
|
+
const bin = atob(b64);
|
|
135
|
+
const bytes = Uint8Array.from(bin, (c) => c.charCodeAt(0));
|
|
136
|
+
return new TextDecoder().decode(bytes);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Supabase SSR cookie: `sb-<ref>-auth-token` (or chunks `.0`, `.1`, … joined in
|
|
140
|
+
* order), the value JSON or `base64-` + base64url(JSON), holding `access_token`.
|
|
141
|
+
*/
|
|
142
|
+
function readSupabaseAccessToken(cookies, baseName) {
|
|
143
|
+
let raw = cookies[baseName];
|
|
144
|
+
if (raw === undefined) {
|
|
145
|
+
const chunks = [];
|
|
146
|
+
for (let i = 0; cookies[`${baseName}.${i}`] !== undefined; i++)
|
|
147
|
+
chunks.push(cookies[`${baseName}.${i}`]);
|
|
148
|
+
if (!chunks.length)
|
|
149
|
+
return undefined;
|
|
150
|
+
raw = chunks.join('');
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
let text = decodeURIComponent(raw);
|
|
154
|
+
if (text.startsWith('base64-'))
|
|
155
|
+
text = decodeBase64Url(text.slice('base64-'.length));
|
|
156
|
+
const parsed = JSON.parse(text);
|
|
157
|
+
const token = Array.isArray(parsed) ? parsed[0] : parsed?.access_token;
|
|
158
|
+
return typeof token === 'string' && token ? token : undefined;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/** Resolve the cookie names / format / bearer flag the bridge uses for its source. */
|
|
165
|
+
function bridgeCookieConfig(options) {
|
|
166
|
+
const presetId = options.preset ?? ((0, migration_presets_1.getMigrationBridgePreset)(options.source) ? options.source : undefined);
|
|
167
|
+
let cookies = [];
|
|
168
|
+
let clear = [];
|
|
169
|
+
let format = 'raw';
|
|
170
|
+
let bearer = false;
|
|
171
|
+
let sharesAtlasCookie = false;
|
|
172
|
+
let issuer = null;
|
|
173
|
+
if (presetId) {
|
|
174
|
+
try {
|
|
175
|
+
const r = (0, migration_presets_1.resolveMigrationBridgePreset)(presetId, options.presetVars ?? {});
|
|
176
|
+
cookies = r.cookies;
|
|
177
|
+
clear = r.clearCookies;
|
|
178
|
+
format = r.tokenFormat;
|
|
179
|
+
bearer = r.bearer;
|
|
180
|
+
sharesAtlasCookie = r.sharesAtlasCookie;
|
|
181
|
+
issuer = r.issuer;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// A preset whose cookie names need variables the app did not pass: only explicit names work.
|
|
185
|
+
const p = (0, migration_presets_1.getMigrationBridgePreset)(presetId);
|
|
186
|
+
cookies = (p?.cookies ?? []).filter((c) => !c.includes('{'));
|
|
187
|
+
clear = (p?.clearCookies ?? p?.cookies ?? []).filter((c) => !c.includes('{'));
|
|
188
|
+
format = p?.tokenFormat ?? 'raw';
|
|
189
|
+
bearer = p?.bearer === true;
|
|
190
|
+
sharesAtlasCookie = p?.sharesAtlasCookie === true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (options.cookieNames)
|
|
194
|
+
cookies = options.cookieNames;
|
|
195
|
+
if (options.clearCookieNames)
|
|
196
|
+
clear = options.clearCookieNames;
|
|
197
|
+
else if (options.cookieNames)
|
|
198
|
+
clear = options.cookieNames;
|
|
199
|
+
return {
|
|
200
|
+
cookies,
|
|
201
|
+
clear,
|
|
202
|
+
format: options.tokenFormat ?? format,
|
|
203
|
+
bearer: options.bearer ?? bearer,
|
|
204
|
+
sharesAtlasCookie: sharesAtlasCookie || cookies.includes('__session'),
|
|
205
|
+
issuer,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* The bridge as a function of a request's headers. Call it from middleware
|
|
210
|
+
* before your normal auth check; it does nothing (no network) for a request
|
|
211
|
+
* without an old session, or with an Atlas session already present.
|
|
212
|
+
*/
|
|
213
|
+
function createMigrationBridge(options) {
|
|
214
|
+
const secure = options.secure !== false;
|
|
215
|
+
const config = bridgeCookieConfig(options);
|
|
216
|
+
const clearOld = (present) => {
|
|
217
|
+
const names = new Set();
|
|
218
|
+
for (const pattern of config.clear) {
|
|
219
|
+
if (!pattern.includes('*')) {
|
|
220
|
+
names.add(pattern);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
for (const name of Object.keys(present))
|
|
224
|
+
if ((0, migration_presets_1.cookieNameMatches)(pattern, name))
|
|
225
|
+
names.add(name);
|
|
226
|
+
}
|
|
227
|
+
return [...names].map((name) => ({
|
|
228
|
+
name,
|
|
229
|
+
value: '',
|
|
230
|
+
options: {
|
|
231
|
+
path: '/',
|
|
232
|
+
maxAge: 0,
|
|
233
|
+
...(options.oldCookieDomain ? { domain: options.oldCookieDomain } : {}),
|
|
234
|
+
...(name.startsWith('__Secure-') || name.startsWith('__Host-') ? { secure: true } : {}),
|
|
235
|
+
},
|
|
236
|
+
}));
|
|
237
|
+
};
|
|
238
|
+
const readToken = async (request, cookies) => {
|
|
239
|
+
if (options.extractToken) {
|
|
240
|
+
const t = await options.extractToken({ cookies, headers: request.headers });
|
|
241
|
+
return t ? { token: t, fromAtlasCookie: false } : undefined;
|
|
242
|
+
}
|
|
243
|
+
for (const pattern of config.cookies) {
|
|
244
|
+
const names = pattern.includes('*') ? Object.keys(cookies).filter((n) => (0, migration_presets_1.cookieNameMatches)(pattern, n)).sort() : [pattern];
|
|
245
|
+
for (const name of names) {
|
|
246
|
+
const token = config.format === 'supabase' ? readSupabaseAccessToken(cookies, name) : cookies[name];
|
|
247
|
+
if (token)
|
|
248
|
+
return { token, fromAtlasCookie: name === '__session' };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (config.bearer) {
|
|
252
|
+
const auth = header(request.headers, 'authorization');
|
|
253
|
+
const m = auth ? /^Bearer\s+(.+)$/i.exec(auth.trim()) : null;
|
|
254
|
+
if (m && config.issuer && peekIss(m[1]) === config.issuer)
|
|
255
|
+
return { token: m[1], fromAtlasCookie: false };
|
|
256
|
+
}
|
|
257
|
+
return undefined;
|
|
258
|
+
};
|
|
259
|
+
return async function bridge(request) {
|
|
260
|
+
const cookies = parseCookieHeader(header(request.headers, 'cookie'));
|
|
261
|
+
const found = await readToken(request, cookies);
|
|
262
|
+
if (!found)
|
|
263
|
+
return { action: 'none' };
|
|
264
|
+
// Already on Atlas: an Atlas refresh cookie means the switch happened.
|
|
265
|
+
if (cookies.__atlas_rt)
|
|
266
|
+
return { action: 'none' };
|
|
267
|
+
// `__session` is Atlas's own cookie name, and a few vendors (Clerk, Firebase
|
|
268
|
+
// Hosting, nextjs-auth0) use it too. A token read from it is the vendor's
|
|
269
|
+
// only when it carries the vendor's issuer (which needs the preset's
|
|
270
|
+
// variables); otherwise an Atlas session (a JWT with another issuer) means
|
|
271
|
+
// the user is already on Atlas.
|
|
272
|
+
if (found.fromAtlasCookie) {
|
|
273
|
+
if (!config.issuer || peekIss(found.token) !== config.issuer)
|
|
274
|
+
return { action: 'none' };
|
|
275
|
+
}
|
|
276
|
+
else if (cookies.__session) {
|
|
277
|
+
const iss = peekIss(cookies.__session);
|
|
278
|
+
const atlasSession = !config.sharesAtlasCookie || (iss !== undefined && iss !== config.issuer);
|
|
279
|
+
if (atlasSession)
|
|
280
|
+
return { action: 'none' };
|
|
281
|
+
}
|
|
282
|
+
const result = await exchangeMigrationSession({
|
|
283
|
+
source: options.source,
|
|
284
|
+
fapiOrigin: options.fapiOrigin,
|
|
285
|
+
publishableKey: options.publishableKey,
|
|
286
|
+
token: found.token,
|
|
287
|
+
fetchImpl: options.fetchImpl,
|
|
288
|
+
userAgent: header(request.headers, 'user-agent'),
|
|
289
|
+
secretKey: options.secretKey,
|
|
290
|
+
bapiBaseUrl: options.bapiBaseUrl,
|
|
291
|
+
clientIp: request.ip ?? clientIpFrom(request.headers),
|
|
292
|
+
});
|
|
293
|
+
if (result.kind === 'session') {
|
|
294
|
+
const old = clearOld(cookies).filter((c) => c.name !== '__session');
|
|
295
|
+
return {
|
|
296
|
+
action: 'signed_in',
|
|
297
|
+
session: result,
|
|
298
|
+
cookies: [
|
|
299
|
+
{ name: '__session', value: result.jwt, options: { path: '/', sameSite: 'lax', secure } },
|
|
300
|
+
{ name: '__atlas_rt', value: result.refreshToken, options: { path: '/', httpOnly: true, sameSite: 'lax', secure } },
|
|
301
|
+
...old,
|
|
302
|
+
],
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
if (result.kind === 'needs_mfa') {
|
|
306
|
+
return {
|
|
307
|
+
action: 'needs_mfa',
|
|
308
|
+
attemptId: result.attemptId,
|
|
309
|
+
status: result.status,
|
|
310
|
+
cookies: clearOld(cookies),
|
|
311
|
+
continuationUrl: (url) => {
|
|
312
|
+
const next = new URL(url);
|
|
313
|
+
next.searchParams.set('__atlas_attempt', result.attemptId);
|
|
314
|
+
next.searchParams.set('__atlas_status', result.status);
|
|
315
|
+
return next.toString();
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return { action: 'refused', outcome: result.outcome, cookies: FINAL.includes(result.outcome) ? clearOld(cookies) : [] };
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/** The client IP a proxy in front of your server recorded (first X-Forwarded-For hop, or X-Real-IP). */
|
|
323
|
+
function clientIpFrom(headers) {
|
|
324
|
+
const xff = header(headers, 'x-forwarded-for');
|
|
325
|
+
const first = xff?.split(',')[0]?.trim();
|
|
326
|
+
return first || header(headers, 'x-real-ip')?.trim() || undefined;
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=migration-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-bridge.js","sourceRoot":"","sources":["../src/migration-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZERO-LOGOUT BRIDGE PRESETS — per vendor, how an old session is recognised.
|
|
3
|
+
*
|
|
4
|
+
* Shared by the Atlas API (which verifies the token and resolves the user) and
|
|
5
|
+
* the SDK middleware (which knows which cookie / header carries it), so both
|
|
6
|
+
* read one table. Pure data plus a few string templates: safe on every runtime.
|
|
7
|
+
*
|
|
8
|
+
* Three modes:
|
|
9
|
+
* - `jwt`: the vendor's session (or a token inside it) is a JWT. Atlas
|
|
10
|
+
* verifies it against the vendor's issuer and keys (JWKS, or an X.509 map
|
|
11
|
+
* like Firebase session cookies use), maps `claims.subject` to the imported
|
|
12
|
+
* user (`external_id` = the source user id), and spends `claims.sessionKey`
|
|
13
|
+
* (`jti` / `sid`, falling back to the whole token) in the single-use ledger.
|
|
14
|
+
* - `session_table`: an opaque token; Atlas looks up sha256(token) among the
|
|
15
|
+
* sessions imported in the migration bundle.
|
|
16
|
+
* - `remote`: the vendor's session can only be checked by asking the vendor
|
|
17
|
+
* with the user's own token (Appwrite, PocketBase): Atlas calls
|
|
18
|
+
* `remote.url` with the token filled into `{token}` and reads the subject
|
|
19
|
+
* (and profile) from the JSON answer by dot path.
|
|
20
|
+
*
|
|
21
|
+
* Templates use `{var}` placeholders filled from the bridge settings'
|
|
22
|
+
* `preset_vars` (e.g. `{domain}`, `{region}`); {@link resolveMigrationBridgePreset}
|
|
23
|
+
* refuses a template with a missing variable.
|
|
24
|
+
*
|
|
25
|
+
* Vendor tracks register their preset (or refine the starter below) with
|
|
26
|
+
* {@link registerMigrationBridgePreset}; a test checks every preset resolves.
|
|
27
|
+
*/
|
|
28
|
+
export interface MigrationBridgeClaims {
|
|
29
|
+
/** Claim holding the source user id (default `sub`). */
|
|
30
|
+
subject: string;
|
|
31
|
+
email?: string;
|
|
32
|
+
emailVerified?: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
/** Claim whose value spends the token in the single-use ledger (`jti`, `sid`); the whole token when absent. */
|
|
35
|
+
sessionKey?: string;
|
|
36
|
+
/**
|
|
37
|
+
* How the vendor says a second factor was passed: `amr:mfa` (the `amr` array
|
|
38
|
+
* contains `mfa`), `acr:<value>`, or `claim:<name>` (a truthy claim).
|
|
39
|
+
*/
|
|
40
|
+
mfa?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* How the middleware gets the token out of the cookie: `raw` (the cookie value
|
|
44
|
+
* is the token), `supabase` (Supabase SSR's `base64-` JSON cookie, possibly
|
|
45
|
+
* chunked `.0`/`.1`, holding `access_token`), or a custom extractor a vendor
|
|
46
|
+
* track registers on the middleware side.
|
|
47
|
+
*/
|
|
48
|
+
export type TokenFormat = 'raw' | 'supabase' | (string & {});
|
|
49
|
+
export interface MigrationBridgePreset {
|
|
50
|
+
id: string;
|
|
51
|
+
label: string;
|
|
52
|
+
mode: 'jwt' | 'session_table' | 'remote';
|
|
53
|
+
/** Variables the templates need, with a one-line hint each. */
|
|
54
|
+
vars?: Record<string, string>;
|
|
55
|
+
/** Optional variables and their defaults. */
|
|
56
|
+
defaults?: Record<string, string>;
|
|
57
|
+
jwt?: {
|
|
58
|
+
issuer: string;
|
|
59
|
+
/** Where the keys are. Omitted → OIDC discovery from the issuer. */
|
|
60
|
+
keysUrl?: string;
|
|
61
|
+
/** `jwks` (default) or `x509` (a `{ kid: PEM certificate }` map). */
|
|
62
|
+
keysFormat?: 'jwks' | 'x509';
|
|
63
|
+
/** Expected `aud` template(s); unchecked when absent. */
|
|
64
|
+
audience?: string[];
|
|
65
|
+
algorithms: string[];
|
|
66
|
+
claims: MigrationBridgeClaims;
|
|
67
|
+
/**
|
|
68
|
+
* Accept a validly signed token this many seconds past `exp` (each one still
|
|
69
|
+
* exchanges once). For vendors whose cookie holds a short-lived token that
|
|
70
|
+
* their client SDK refreshes and nothing refreshes after the switch. 0 by default.
|
|
71
|
+
*/
|
|
72
|
+
expiredGraceSeconds?: number;
|
|
73
|
+
/** The vendor may sign with a shared secret (HS256) instead of keys (Supabase legacy JWT secret). */
|
|
74
|
+
allowSharedSecret?: boolean;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Mode `remote`: the vendor call that vouches for a token. Templates take the
|
|
78
|
+
* preset variables; `{token}` is the presented token and is filled only at
|
|
79
|
+
* call time, by the server.
|
|
80
|
+
*/
|
|
81
|
+
remote?: MigrationBridgeRemote;
|
|
82
|
+
/**
|
|
83
|
+
* Cookies that may carry the token, most specific first. `*` matches any run
|
|
84
|
+
* of characters (Amplify names cookies per client id and username).
|
|
85
|
+
*/
|
|
86
|
+
cookies: string[];
|
|
87
|
+
tokenFormat?: TokenFormat;
|
|
88
|
+
/** Read `Authorization: Bearer` too (API clients holding the old token). */
|
|
89
|
+
bearer?: boolean;
|
|
90
|
+
/** Cookies to clear once exchanged (defaults to `cookies`). */
|
|
91
|
+
clearCookies?: string[];
|
|
92
|
+
/**
|
|
93
|
+
* The cookie name collides with Atlas's own (`__session`): the middleware
|
|
94
|
+
* only treats it as the old vendor's when the token's `iss` is the vendor's.
|
|
95
|
+
*/
|
|
96
|
+
sharesAtlasCookie?: boolean;
|
|
97
|
+
/** Integrator-facing notes (what must be configured at the vendor, caveats). */
|
|
98
|
+
notes?: string;
|
|
99
|
+
}
|
|
100
|
+
/** How a `remote` preset asks the vendor about a token. */
|
|
101
|
+
export interface MigrationBridgeRemote {
|
|
102
|
+
/** URL template (`{var}` from the preset variables, `{token}` at call time). */
|
|
103
|
+
url: string;
|
|
104
|
+
method: 'GET' | 'POST';
|
|
105
|
+
/** Header templates, e.g. `{ authorization: 'Bearer {token}' }`. */
|
|
106
|
+
headers?: Record<string, string>;
|
|
107
|
+
/** Body template (POST). */
|
|
108
|
+
body?: string;
|
|
109
|
+
/** Dot path into the JSON answer holding the source user id (`record.id`, `$id`). */
|
|
110
|
+
subjectPath: string;
|
|
111
|
+
emailPath?: string;
|
|
112
|
+
emailVerifiedPath?: string;
|
|
113
|
+
namePath?: string;
|
|
114
|
+
}
|
|
115
|
+
export declare function registerMigrationBridgePreset(preset: MigrationBridgePreset, options?: {
|
|
116
|
+
replace?: boolean;
|
|
117
|
+
}): void;
|
|
118
|
+
export declare function getMigrationBridgePreset(id: string): MigrationBridgePreset | undefined;
|
|
119
|
+
export declare function listMigrationBridgePresets(): MigrationBridgePreset[];
|
|
120
|
+
/** The bridge settings a preset resolves to, every template filled in. */
|
|
121
|
+
export interface ResolvedBridgePreset {
|
|
122
|
+
preset: string;
|
|
123
|
+
mode: 'jwt' | 'session_table' | 'remote';
|
|
124
|
+
issuer: string | null;
|
|
125
|
+
keysUrl: string | null;
|
|
126
|
+
keysFormat: 'jwks' | 'x509';
|
|
127
|
+
audience: string[] | null;
|
|
128
|
+
algorithms: string[];
|
|
129
|
+
claims: MigrationBridgeClaims;
|
|
130
|
+
expiredGraceSeconds: number;
|
|
131
|
+
cookies: string[];
|
|
132
|
+
tokenFormat: TokenFormat;
|
|
133
|
+
bearer: boolean;
|
|
134
|
+
clearCookies: string[];
|
|
135
|
+
sharesAtlasCookie: boolean;
|
|
136
|
+
/** Mode `remote`: the vendor call, preset variables filled, `{token}` left for the server. */
|
|
137
|
+
remote: MigrationBridgeRemote | null;
|
|
138
|
+
}
|
|
139
|
+
export declare class PresetVariableError extends Error {
|
|
140
|
+
readonly variable: string;
|
|
141
|
+
constructor(variable: string, message: string);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Fill a preset's templates. Throws {@link PresetVariableError} for a missing or
|
|
145
|
+
* malformed variable. Values are trimmed; a trailing slash on a URL-ish value
|
|
146
|
+
* is removed (`https://example.com/` → `https://example.com`).
|
|
147
|
+
*/
|
|
148
|
+
export declare function resolveMigrationBridgePreset(id: string, rawVars?: Record<string, string>): ResolvedBridgePreset;
|
|
149
|
+
/** Does a cookie name match a preset pattern (`*` = any run of characters)? */
|
|
150
|
+
export declare function cookieNameMatches(pattern: string, name: string): boolean;
|