postex-auth-sdk 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 +94 -0
- package/dist/postex-auth-sdk.es.js +632 -0
- package/dist/postex-auth-sdk.es.js.map +1 -0
- package/dist/postex-auth-sdk.iife.js +2 -0
- package/dist/postex-auth-sdk.iife.js.map +1 -0
- package/dist/postex-auth-sdk.umd.js +2 -0
- package/dist/postex-auth-sdk.umd.js.map +1 -0
- package/dist/vite.svg +1 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# PostEx Auth SDK
|
|
2
|
+
|
|
3
|
+
PostEx Auth SDK for authentication flows: OTP, magic links, passkeys (WebAuthn), and token management. Use it in any frontend project via NPM or CDN.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### NPM
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install postex-auth-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### CDN (jsDelivr)
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<script src="https://cdn.jsdelivr.net/npm/postex-auth-sdk@1/dist/postex-auth-sdk.umd.js"></script>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### CDN (unpkg)
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<script src="https://unpkg.com/postex-auth-sdk@1/dist/postex-auth-sdk.umd.js"></script>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Use a specific version for production (e.g. `@1.0.0` instead of `@1`).
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Via CDN (script tag)
|
|
30
|
+
|
|
31
|
+
After loading the script, the SDK is available on the global `PostexAuthSDK` object:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<script src="https://cdn.jsdelivr.net/npm/postex-auth-sdk@1/dist/postex-auth-sdk.umd.js"></script>
|
|
35
|
+
<script>
|
|
36
|
+
const { AuthSDK, WebAuthn } = PostexAuthSDK;
|
|
37
|
+
const sdk = new AuthSDK({ apiKey: "your-api-key" });
|
|
38
|
+
|
|
39
|
+
// Check auth status
|
|
40
|
+
const status = await sdk.getStatus("user@example.com");
|
|
41
|
+
|
|
42
|
+
// Initiate auth (OTP or WebAuthn)
|
|
43
|
+
const result = await sdk.initiateAuth("user@example.com");
|
|
44
|
+
if (result.status === "webauthn_challenge") {
|
|
45
|
+
const authResult = await sdk.authenticateWithPasskey({
|
|
46
|
+
challenge: result.challenge,
|
|
47
|
+
rp: result.rp,
|
|
48
|
+
credentialIds: result.credentialIds || [],
|
|
49
|
+
});
|
|
50
|
+
} else if (result.status === "otp_sent") {
|
|
51
|
+
const verified = await sdk.verifyOTP("123456");
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Via NPM (ESM)
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
import { AuthSDK, WebAuthn, AuthSDKFetchError } from "postex-auth-sdk";
|
|
60
|
+
|
|
61
|
+
const sdk = new AuthSDK({ apiKey: "your-api-key" });
|
|
62
|
+
|
|
63
|
+
// Use SDK methods
|
|
64
|
+
const status = await sdk.getStatus("user@example.com");
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### WebAuthn utilities
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
import { WebAuthn } from "postex-auth-sdk";
|
|
71
|
+
|
|
72
|
+
if (WebAuthn.isWebAuthnSupported()) {
|
|
73
|
+
const conditionalUI = await WebAuthn.isConditionalUISupported();
|
|
74
|
+
// ...
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## API overview
|
|
79
|
+
|
|
80
|
+
- **AuthSDK** – Main client: `getStatus`, `initiateAuth`, `verifyOTP`, `verifyMagicLink`, `completeMagicLink`, `authenticateWithPasskey`, `registerPasskey`, `getPasskeyStatus`, `removePasskey`, `getRequestAuthHeaders`, `authenticatedFetch`, `refreshToken`, `logout`, `getAccessToken`, `storeTokens`, `clearTokens`
|
|
81
|
+
- **WebAuthn** – Helpers: `isWebAuthnSupported`, `isConditionalUISupported`, base64/ArrayBuffer conversion, DPoP key and proof helpers, passkey email storage
|
|
82
|
+
- **AuthSDKFetchError** – Error class with `response.status` and `response.data`
|
|
83
|
+
|
|
84
|
+
## Versioning
|
|
85
|
+
|
|
86
|
+
This package follows [semantic versioning](https://semver.org/). CDN URLs support:
|
|
87
|
+
|
|
88
|
+
- `@1` – latest 1.x.x
|
|
89
|
+
- `@1.0` – latest 1.0.x
|
|
90
|
+
- `@1.0.0` – exact version
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
function q() {
|
|
2
|
+
return typeof window < "u" && typeof window.PublicKeyCredential < "u" && typeof navigator < "u" && typeof navigator.credentials < "u";
|
|
3
|
+
}
|
|
4
|
+
async function W() {
|
|
5
|
+
if (!q()) return !1;
|
|
6
|
+
try {
|
|
7
|
+
return await PublicKeyCredential.isConditionalMediationAvailable?.() ?? !1;
|
|
8
|
+
} catch {
|
|
9
|
+
return !1;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function h(o) {
|
|
13
|
+
const n = new Uint8Array(o);
|
|
14
|
+
let t = "";
|
|
15
|
+
for (let e = 0; e < n.byteLength; e++)
|
|
16
|
+
t += String.fromCharCode(n[e]);
|
|
17
|
+
return btoa(t);
|
|
18
|
+
}
|
|
19
|
+
function k(o) {
|
|
20
|
+
if (typeof o != "string" || !o)
|
|
21
|
+
throw new Error("Invalid base64: expected non-empty string");
|
|
22
|
+
const n = o.replace(/\s/g, "").replace(/-/g, "+").replace(/_/g, "/"), t = n.length % 4, e = t > 0 ? n + "=".repeat(4 - t) : n;
|
|
23
|
+
try {
|
|
24
|
+
const a = atob(e), r = new Uint8Array(a.length);
|
|
25
|
+
for (let s = 0; s < a.length; s++)
|
|
26
|
+
r[s] = a.charCodeAt(s);
|
|
27
|
+
return r.buffer;
|
|
28
|
+
} catch {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"Invalid base64: string is not correctly encoded. Check challenge/credentialId from server."
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function w(o) {
|
|
35
|
+
return h(o).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
36
|
+
}
|
|
37
|
+
function R(o) {
|
|
38
|
+
return /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(
|
|
39
|
+
o
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
function C(o) {
|
|
43
|
+
const n = o.replace(/-/g, ""), t = new Uint8Array(n.length / 2);
|
|
44
|
+
for (let e = 0; e < t.length; e++)
|
|
45
|
+
t[e] = parseInt(n.substr(e * 2, 2), 16);
|
|
46
|
+
return t.buffer;
|
|
47
|
+
}
|
|
48
|
+
function Y(o) {
|
|
49
|
+
if (!o || typeof o != "string")
|
|
50
|
+
throw new Error("Invalid input: expected non-empty string");
|
|
51
|
+
return R(o) ? C(o) : k(o);
|
|
52
|
+
}
|
|
53
|
+
function x(o) {
|
|
54
|
+
return new TextEncoder().encode(o).buffer;
|
|
55
|
+
}
|
|
56
|
+
function F(o) {
|
|
57
|
+
return String.fromCharCode(...o);
|
|
58
|
+
}
|
|
59
|
+
const B = "xpay_webauthn", $ = 1, d = "passkey_data", S = "passkey_email";
|
|
60
|
+
function p() {
|
|
61
|
+
return new Promise((o, n) => {
|
|
62
|
+
const t = indexedDB.open(B, $);
|
|
63
|
+
t.onerror = () => n(t.error), t.onsuccess = () => o(t.result), t.onupgradeneeded = () => {
|
|
64
|
+
const e = t.result;
|
|
65
|
+
e.objectStoreNames.contains(d) || e.createObjectStore(d);
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async function G() {
|
|
70
|
+
try {
|
|
71
|
+
const o = await p();
|
|
72
|
+
return new Promise((n, t) => {
|
|
73
|
+
const e = o.transaction(d, "readonly"), r = e.objectStore(d).get(S);
|
|
74
|
+
r.onerror = () => t(r.error), r.onsuccess = () => n(r.result ?? null), e.oncomplete = () => o.close();
|
|
75
|
+
});
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function M(o) {
|
|
81
|
+
try {
|
|
82
|
+
const n = await p();
|
|
83
|
+
return new Promise((t, e) => {
|
|
84
|
+
const a = n.transaction(d, "readwrite"), s = a.objectStore(d).put(o, S);
|
|
85
|
+
s.onerror = () => e(s.error), s.onsuccess = () => t(), a.oncomplete = () => n.close();
|
|
86
|
+
});
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function V() {
|
|
91
|
+
try {
|
|
92
|
+
const o = await p();
|
|
93
|
+
return new Promise((n, t) => {
|
|
94
|
+
const e = o.transaction(d, "readwrite"), r = e.objectStore(d).delete(S);
|
|
95
|
+
r.onerror = () => t(r.error), r.onsuccess = () => n(), e.oncomplete = () => o.close();
|
|
96
|
+
});
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const E = "dpop_private_key", I = "dpop_public_key_jwk";
|
|
101
|
+
function U(o) {
|
|
102
|
+
return {
|
|
103
|
+
kty: "EC",
|
|
104
|
+
crv: "P-256",
|
|
105
|
+
x: o.x,
|
|
106
|
+
y: o.y
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async function N(o) {
|
|
110
|
+
const n = JSON.stringify({
|
|
111
|
+
crv: o.crv,
|
|
112
|
+
kty: o.kty,
|
|
113
|
+
x: o.x,
|
|
114
|
+
y: o.y
|
|
115
|
+
}), t = await crypto.subtle.digest(
|
|
116
|
+
"SHA-256",
|
|
117
|
+
new TextEncoder().encode(n)
|
|
118
|
+
);
|
|
119
|
+
return w(t);
|
|
120
|
+
}
|
|
121
|
+
async function D(o) {
|
|
122
|
+
try {
|
|
123
|
+
const n = await p();
|
|
124
|
+
return new Promise((t, e) => {
|
|
125
|
+
const a = n.transaction(d, "readwrite"), s = a.objectStore(d).put(o, E);
|
|
126
|
+
s.onerror = () => e(s.error), s.onsuccess = () => t(), a.oncomplete = () => n.close();
|
|
127
|
+
});
|
|
128
|
+
} catch (n) {
|
|
129
|
+
console.error("Failed to store DPoP private key:", n);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function J(o) {
|
|
133
|
+
try {
|
|
134
|
+
const n = await p();
|
|
135
|
+
return new Promise((t, e) => {
|
|
136
|
+
const a = n.transaction(d, "readwrite"), s = a.objectStore(d).put(o, I);
|
|
137
|
+
s.onerror = () => e(s.error), s.onsuccess = () => t(), a.oncomplete = () => n.close();
|
|
138
|
+
});
|
|
139
|
+
} catch (n) {
|
|
140
|
+
console.error("Failed to store DPoP public key JWK:", n);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function v() {
|
|
144
|
+
try {
|
|
145
|
+
const o = await p();
|
|
146
|
+
return new Promise((n, t) => {
|
|
147
|
+
const e = o.transaction(d, "readonly"), r = e.objectStore(d).get(E);
|
|
148
|
+
r.onerror = () => t(r.error), r.onsuccess = () => n(r.result ?? null), e.oncomplete = () => o.close();
|
|
149
|
+
});
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function j() {
|
|
155
|
+
try {
|
|
156
|
+
const o = await p();
|
|
157
|
+
return new Promise((n, t) => {
|
|
158
|
+
const e = o.transaction(d, "readonly"), r = e.objectStore(d).get(I);
|
|
159
|
+
r.onerror = () => t(r.error), r.onsuccess = () => n(r.result ?? null), e.oncomplete = () => o.close();
|
|
160
|
+
});
|
|
161
|
+
} catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function L() {
|
|
166
|
+
try {
|
|
167
|
+
const o = await p();
|
|
168
|
+
return new Promise((n, t) => {
|
|
169
|
+
const e = o.transaction(d, "readwrite"), a = e.objectStore(d);
|
|
170
|
+
a.delete(E), a.delete(I), e.onerror = () => t(e.error), e.oncomplete = () => {
|
|
171
|
+
o.close(), n();
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function _() {
|
|
178
|
+
const o = await crypto.subtle.generateKey(
|
|
179
|
+
{
|
|
180
|
+
name: "ECDSA",
|
|
181
|
+
namedCurve: "P-256"
|
|
182
|
+
},
|
|
183
|
+
!1,
|
|
184
|
+
// Private key is non-extractable
|
|
185
|
+
["sign", "verify"]
|
|
186
|
+
), n = await crypto.subtle.exportKey("jwk", o.publicKey), t = U(n), e = await N(t);
|
|
187
|
+
return await D(o.privateKey), await J(t), { publicKey: t, thumbprint: e };
|
|
188
|
+
}
|
|
189
|
+
async function b(o, n, t) {
|
|
190
|
+
try {
|
|
191
|
+
const e = await v(), a = await j();
|
|
192
|
+
if (!e || !a) return null;
|
|
193
|
+
const r = {
|
|
194
|
+
typ: "dpop+jwt",
|
|
195
|
+
alg: "ES256",
|
|
196
|
+
jwk: a
|
|
197
|
+
// Public key in JWK format
|
|
198
|
+
}, s = new URL(
|
|
199
|
+
n,
|
|
200
|
+
typeof window < "u" ? window.location.origin : void 0
|
|
201
|
+
), i = `${s.origin}${s.pathname}`, u = {
|
|
202
|
+
jti: crypto.randomUUID(),
|
|
203
|
+
htm: o.toUpperCase(),
|
|
204
|
+
htu: i,
|
|
205
|
+
iat: Math.floor(Date.now() / 1e3)
|
|
206
|
+
};
|
|
207
|
+
if (t) {
|
|
208
|
+
const m = new TextEncoder().encode(t), O = await crypto.subtle.digest("SHA-256", m);
|
|
209
|
+
u.ath = w(O);
|
|
210
|
+
}
|
|
211
|
+
const y = w(
|
|
212
|
+
new TextEncoder().encode(JSON.stringify(r)).buffer
|
|
213
|
+
), c = w(
|
|
214
|
+
new TextEncoder().encode(JSON.stringify(u)).buffer
|
|
215
|
+
), l = `${y}.${c}`, g = await crypto.subtle.sign(
|
|
216
|
+
{
|
|
217
|
+
name: "ECDSA",
|
|
218
|
+
hash: { name: "SHA-256" }
|
|
219
|
+
},
|
|
220
|
+
e,
|
|
221
|
+
new TextEncoder().encode(l)
|
|
222
|
+
), T = w(g);
|
|
223
|
+
return `${y}.${c}.${T}`;
|
|
224
|
+
} catch (e) {
|
|
225
|
+
return console.error("Failed to generate DPoP proof:", e), null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async function z() {
|
|
229
|
+
return await v() !== null;
|
|
230
|
+
}
|
|
231
|
+
const X = D, P = "postex-auth-token", f = "http://localhost:3200";
|
|
232
|
+
class H extends Error {
|
|
233
|
+
constructor(n, t, e) {
|
|
234
|
+
super(e ?? `Request failed with status ${n}`), this.response = { status: n, data: t }, this.name = "AuthSDKFetchError";
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const A = "auth_sdk_id_token", K = "auth_sdk_refresh_token";
|
|
238
|
+
class Q {
|
|
239
|
+
constructor(n) {
|
|
240
|
+
this.config = n;
|
|
241
|
+
}
|
|
242
|
+
buildUrl(n, t) {
|
|
243
|
+
const e = f.replace(/\/$/, ""), a = n.startsWith("/") ? n : `/${n}`, r = `${e}${a}`;
|
|
244
|
+
if (!t || Object.keys(t).length === 0) return r;
|
|
245
|
+
const s = new URLSearchParams(t).toString();
|
|
246
|
+
return `${r}?${s}`;
|
|
247
|
+
}
|
|
248
|
+
async request(n, t, e) {
|
|
249
|
+
const a = this.buildUrl(t, e?.params), r = {
|
|
250
|
+
"Content-Type": "application/json",
|
|
251
|
+
Accept: "application/json",
|
|
252
|
+
"X-API-Key": this.config.apiKey ?? "",
|
|
253
|
+
...e?.headers
|
|
254
|
+
}, s = {
|
|
255
|
+
method: n,
|
|
256
|
+
credentials: "include",
|
|
257
|
+
headers: r
|
|
258
|
+
};
|
|
259
|
+
e?.body !== void 0 && e?.body !== null && (s.body = JSON.stringify(e.body));
|
|
260
|
+
const i = await fetch(a, s);
|
|
261
|
+
if (!i.ok) {
|
|
262
|
+
let c;
|
|
263
|
+
try {
|
|
264
|
+
const l = await i.text();
|
|
265
|
+
c = l ? JSON.parse(l) : void 0;
|
|
266
|
+
} catch {
|
|
267
|
+
c = void 0;
|
|
268
|
+
}
|
|
269
|
+
throw i.status === 401 && await this.clearTokens(), new H(i.status, c);
|
|
270
|
+
}
|
|
271
|
+
const u = await i.text();
|
|
272
|
+
return { data: u ? JSON.parse(u) : {} };
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Returns auth headers (Authorization + DPoP) for the given request.
|
|
276
|
+
* Use this to attach auth to your own HTTP client (e.g. axios request interceptor).
|
|
277
|
+
* @param method - HTTP method (e.g. "GET", "POST")
|
|
278
|
+
* @param url - Full request URL
|
|
279
|
+
*/
|
|
280
|
+
async getRequestAuthHeaders(n, t) {
|
|
281
|
+
const e = localStorage.getItem(P);
|
|
282
|
+
if (!e) return {};
|
|
283
|
+
const a = t.startsWith("http") ? t : `${f}${t}`, r = await b(
|
|
284
|
+
n.toUpperCase(),
|
|
285
|
+
a,
|
|
286
|
+
e
|
|
287
|
+
), s = {
|
|
288
|
+
Authorization: `Bearer ${e}`
|
|
289
|
+
};
|
|
290
|
+
return r && (s.DPoP = r), s;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* GET /auth/status - Check if client has trusted device session and what auth method is available.
|
|
294
|
+
* Returns no_session | session_found | webauthn_ready per PostEx Auth BFF spec.
|
|
295
|
+
*/
|
|
296
|
+
async getStatus(n) {
|
|
297
|
+
const t = await this.request("GET", "/auth/status", {
|
|
298
|
+
params: { email: n }
|
|
299
|
+
});
|
|
300
|
+
return t.data.data ?? t.data;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* POST /auth/initiate - Unified entry: returns webauthn_challenge or otp_sent.
|
|
304
|
+
* Sets auth_session cookie when otp_sent.
|
|
305
|
+
*/
|
|
306
|
+
async initiateAuth(n) {
|
|
307
|
+
const t = await this.request("POST", "/auth/initiate", {
|
|
308
|
+
body: { email: n }
|
|
309
|
+
}), e = t.data.data ?? t.data;
|
|
310
|
+
return {
|
|
311
|
+
status: e.status,
|
|
312
|
+
challenge: e.challenge,
|
|
313
|
+
credentialIds: e.credentialIds,
|
|
314
|
+
rp: e.rp
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* POST /otp/verify - Verifies the OTP code entered by the user.
|
|
319
|
+
* Stores tokens from the response.
|
|
320
|
+
*/
|
|
321
|
+
async verifyOTP(n) {
|
|
322
|
+
await _();
|
|
323
|
+
const t = await b(
|
|
324
|
+
"POST",
|
|
325
|
+
`${f}/otp/verify`
|
|
326
|
+
), e = await this.request("POST", "/otp/verify", {
|
|
327
|
+
body: { otp: n },
|
|
328
|
+
headers: t ? { DPoP: t } : {}
|
|
329
|
+
}), a = e.data.data ?? e.data, r = a.AuthenticationResult ?? a, s = r.access_token ?? r.accessToken ?? r.AccessToken, i = r.refresh_token ?? r.refreshToken ?? r.RefreshToken, u = r.id_token ?? r.idToken ?? r.IdToken, y = r.expires_in ?? r.expiresIn ?? r.ExpiresIn ?? 3600, c = r.token_type ?? r.tokenType ?? r.TokenType ?? "Bearer";
|
|
330
|
+
return s && await this.storeTokens({
|
|
331
|
+
accessToken: s,
|
|
332
|
+
refreshToken: i ?? "",
|
|
333
|
+
idToken: u ?? "",
|
|
334
|
+
expiresIn: y ?? 3600,
|
|
335
|
+
tokenType: c ?? "Bearer"
|
|
336
|
+
}), {
|
|
337
|
+
access_token: s,
|
|
338
|
+
refresh_token: i ?? "",
|
|
339
|
+
id_token: u ?? "",
|
|
340
|
+
expires_in: y,
|
|
341
|
+
token_type: c,
|
|
342
|
+
verified: r.verified ?? r.Verified ?? !0,
|
|
343
|
+
email: r.email ?? r.Email ?? "",
|
|
344
|
+
...r
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* GET /magic-link - Verify a magic link token.
|
|
349
|
+
* Sets auth_session cookie on success.
|
|
350
|
+
*/
|
|
351
|
+
async verifyMagicLink(n, t) {
|
|
352
|
+
await this.request("GET", "/verify/magic-link", {
|
|
353
|
+
params: { token: n, email: t, redirect_mode: "frontend" }
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* POST /magic-link/complete - Complete magic link authentication.
|
|
358
|
+
* Requires auth_session cookie set by verifyMagicLink.
|
|
359
|
+
* Stores tokens from the response.
|
|
360
|
+
*/
|
|
361
|
+
async completeMagicLink() {
|
|
362
|
+
const n = await this.request(
|
|
363
|
+
"POST",
|
|
364
|
+
"/verify/magic-link/complete",
|
|
365
|
+
{
|
|
366
|
+
body: {}
|
|
367
|
+
}
|
|
368
|
+
), t = n.data.data ?? n.data, e = t.AuthenticationResult ?? t, a = e.access_token ?? e.accessToken ?? e.AccessToken, r = e.refresh_token ?? e.refreshToken ?? e.RefreshToken, s = e.id_token ?? e.idToken ?? e.IdToken, i = e.expires_in ?? e.expiresIn ?? e.ExpiresIn ?? 3600, u = e.token_type ?? e.tokenType ?? e.TokenType ?? "Bearer";
|
|
369
|
+
return a && await this.storeTokens({
|
|
370
|
+
accessToken: a,
|
|
371
|
+
refreshToken: r ?? "",
|
|
372
|
+
idToken: s ?? "",
|
|
373
|
+
expiresIn: i ?? 3600,
|
|
374
|
+
tokenType: u ?? "Bearer"
|
|
375
|
+
}), {
|
|
376
|
+
access_token: a,
|
|
377
|
+
refresh_token: r ?? "",
|
|
378
|
+
id_token: s ?? "",
|
|
379
|
+
expires_in: i,
|
|
380
|
+
token_type: u,
|
|
381
|
+
verified: e.verified ?? e.Verified ?? !0,
|
|
382
|
+
email: e.email ?? e.Email ?? "",
|
|
383
|
+
...e
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
async initiatePasskeyRegistration() {
|
|
387
|
+
const n = await this.request(
|
|
388
|
+
"POST",
|
|
389
|
+
"/webauthn/initiate/challenge",
|
|
390
|
+
{
|
|
391
|
+
body: {}
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
return n.data.data ?? n.data;
|
|
395
|
+
}
|
|
396
|
+
async registerPasskey(n) {
|
|
397
|
+
const t = await this.initiatePasskeyRegistration();
|
|
398
|
+
let e;
|
|
399
|
+
if (t?.user?.id)
|
|
400
|
+
try {
|
|
401
|
+
e = k(t.user.id);
|
|
402
|
+
} catch {
|
|
403
|
+
e = x(t.user.id);
|
|
404
|
+
}
|
|
405
|
+
else
|
|
406
|
+
e = x(n);
|
|
407
|
+
const a = (t.pubKeyCredParams ?? [
|
|
408
|
+
{ type: "public-key", alg: -7 },
|
|
409
|
+
{ type: "public-key", alg: -257 }
|
|
410
|
+
]).map((l) => ({
|
|
411
|
+
type: "public-key",
|
|
412
|
+
alg: l.alg
|
|
413
|
+
}));
|
|
414
|
+
t.excludeCredentials?.map((l) => ({
|
|
415
|
+
type: "public-key",
|
|
416
|
+
id: k(l.id),
|
|
417
|
+
transports: l.transports
|
|
418
|
+
}));
|
|
419
|
+
const r = {
|
|
420
|
+
challenge: k(t.challenge),
|
|
421
|
+
rp: {
|
|
422
|
+
name: t.rp?.name ?? "XPay",
|
|
423
|
+
id: t.rp?.id ?? window.location.hostname
|
|
424
|
+
},
|
|
425
|
+
user: {
|
|
426
|
+
id: e,
|
|
427
|
+
name: t.user?.name ?? n,
|
|
428
|
+
displayName: t.user?.displayName ?? n
|
|
429
|
+
},
|
|
430
|
+
pubKeyCredParams: a,
|
|
431
|
+
timeout: t.timeout ?? 6e4,
|
|
432
|
+
attestation: t.attestation ?? "none",
|
|
433
|
+
authenticatorSelection: t.authenticatorSelection ?? {
|
|
434
|
+
residentKey: "required",
|
|
435
|
+
userVerification: "required"
|
|
436
|
+
}
|
|
437
|
+
}, s = await navigator.credentials.create({
|
|
438
|
+
publicKey: r
|
|
439
|
+
});
|
|
440
|
+
if (!s) throw new Error("Credential creation failed");
|
|
441
|
+
const i = s.response, u = {
|
|
442
|
+
clientDataJSON: h(i.clientDataJSON),
|
|
443
|
+
attestationObject: h(i.attestationObject),
|
|
444
|
+
rawId: h(s.rawId)
|
|
445
|
+
};
|
|
446
|
+
if (!u.rawId) throw new Error("Raw ID is required");
|
|
447
|
+
await _();
|
|
448
|
+
const y = await b(
|
|
449
|
+
"POST",
|
|
450
|
+
`${f}/webauthn/register/challenge`
|
|
451
|
+
), c = await this.request(
|
|
452
|
+
"POST",
|
|
453
|
+
"/webauthn/register/challenge",
|
|
454
|
+
{
|
|
455
|
+
body: u,
|
|
456
|
+
headers: y ? { DPoP: y } : {}
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
return c.data.data ?? c.data;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* POST /webauthn/authenticate/challenge - Authenticate with passkey.
|
|
463
|
+
*/
|
|
464
|
+
async authenticateWithPasskey({
|
|
465
|
+
challenge: n,
|
|
466
|
+
rp: t,
|
|
467
|
+
credentialIds: e
|
|
468
|
+
}) {
|
|
469
|
+
const a = await navigator.credentials.get({
|
|
470
|
+
publicKey: {
|
|
471
|
+
challenge: k(n),
|
|
472
|
+
rpId: t?.host ?? void 0,
|
|
473
|
+
allowCredentials: e.map((m) => ({
|
|
474
|
+
type: "public-key",
|
|
475
|
+
id: k(m)
|
|
476
|
+
// Hint browser about possible transports for faster authenticator discovery
|
|
477
|
+
// transports: ["internal", "hybrid"] as AuthenticatorTransport[],
|
|
478
|
+
})),
|
|
479
|
+
timeout: 6e4,
|
|
480
|
+
userVerification: "required"
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
if (!a) throw new Error("Authentication failed");
|
|
484
|
+
const r = a.response, s = {
|
|
485
|
+
clientDataJSON: h(r.clientDataJSON),
|
|
486
|
+
authenticatorData: h(
|
|
487
|
+
r.authenticatorData
|
|
488
|
+
),
|
|
489
|
+
signature: h(r.signature),
|
|
490
|
+
rawId: h(a.rawId),
|
|
491
|
+
userHandle: r.userHandle ? h(r.userHandle) : ""
|
|
492
|
+
};
|
|
493
|
+
await _();
|
|
494
|
+
const i = await b(
|
|
495
|
+
"POST",
|
|
496
|
+
`${f}/webauthn/authenticate/challenge`
|
|
497
|
+
), u = await this.request(
|
|
498
|
+
"POST",
|
|
499
|
+
"/webauthn/authenticate/challenge",
|
|
500
|
+
{
|
|
501
|
+
body: s,
|
|
502
|
+
headers: i ? { DPoP: i } : {}
|
|
503
|
+
}
|
|
504
|
+
), y = u.data.data ?? u.data, c = y.AuthenticationResult ?? y, l = c.AccessToken ?? c.accessToken ?? c.access_token, g = c.RefreshToken ?? c.refreshToken ?? c.refresh_token, T = c.IdToken ?? c.idToken ?? c.id_token;
|
|
505
|
+
return l && await this.storeTokens({
|
|
506
|
+
accessToken: l,
|
|
507
|
+
refreshToken: g ?? "",
|
|
508
|
+
idToken: T ?? "",
|
|
509
|
+
expiresIn: c.expiresIn ?? c.ExpiresIn ?? 3600,
|
|
510
|
+
tokenType: c.tokenType ?? c.token_type ?? "Bearer"
|
|
511
|
+
}), {
|
|
512
|
+
access_token: l,
|
|
513
|
+
refresh_token: g ?? "",
|
|
514
|
+
id_token: T,
|
|
515
|
+
email: c.email,
|
|
516
|
+
name: c.name ?? c.userName,
|
|
517
|
+
expiresIn: c.expiresIn ?? c.ExpiresIn,
|
|
518
|
+
tokenType: c.tokenType ?? c.token_type,
|
|
519
|
+
...c
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* GET /webauthn/credentials/:username - Get user's passkey status.
|
|
524
|
+
*/
|
|
525
|
+
async getPasskeyStatus(n) {
|
|
526
|
+
const e = `/webauthn/credentials/${encodeURIComponent(n)}`, a = await this.signRequest("GET", e), r = await this.request("GET", e, {
|
|
527
|
+
headers: a.headers
|
|
528
|
+
}), s = r.data.data ?? r.data;
|
|
529
|
+
return {
|
|
530
|
+
...s,
|
|
531
|
+
hasCredentials: !!(s.hasCredentials ?? s.credentialId)
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* DELETE /webauthn/credentials/:username - Remove passkey.
|
|
536
|
+
*/
|
|
537
|
+
async removePasskey(n) {
|
|
538
|
+
const e = `/webauthn/credentials/${encodeURIComponent(n)}`, a = await this.signRequest("DELETE", e);
|
|
539
|
+
await this.request("DELETE", e, {
|
|
540
|
+
headers: a.headers
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Signs a request with DPoP and Authorization headers (internal use).
|
|
545
|
+
*/
|
|
546
|
+
async signRequest(n, t, e = {}) {
|
|
547
|
+
const a = t.startsWith("http") ? t : `${f}${t}`, r = await this.getRequestAuthHeaders(n, a);
|
|
548
|
+
return { ...e, headers: { ...e.headers, ...r } };
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Replaces native fetch or Axios with a DPoP-signed version.
|
|
552
|
+
*/
|
|
553
|
+
async authenticatedFetch(n, t) {
|
|
554
|
+
const e = typeof n == "string" ? n : n instanceof URL ? n.toString() : n.url, a = t?.method || "GET", r = await this.signRequest(a, e, {
|
|
555
|
+
headers: t?.headers
|
|
556
|
+
});
|
|
557
|
+
return fetch(n, { ...t, headers: r.headers });
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Store tokens from /webauthn/authenticate (per spec: sessionStorage preferred).
|
|
561
|
+
*/
|
|
562
|
+
async storeTokens(n) {
|
|
563
|
+
localStorage.setItem(P, n.accessToken), n.refreshToken && localStorage.setItem(K, n.refreshToken), n.idToken && localStorage.setItem(A, n.idToken);
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Clear stored tokens (call on logout).
|
|
567
|
+
*/
|
|
568
|
+
async clearTokens() {
|
|
569
|
+
localStorage.removeItem(P), localStorage.removeItem(A), localStorage.removeItem(K);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* POST /auth/refresh - Refresh access token using server-stored refresh token.
|
|
573
|
+
* Requires trusted device cookie (td). Refresh token is stored server-side.
|
|
574
|
+
* Rate limit: 10 requests per minute.
|
|
575
|
+
*/
|
|
576
|
+
async refreshToken() {
|
|
577
|
+
const n = await this.request("POST", "/auth/refresh", {
|
|
578
|
+
body: {}
|
|
579
|
+
}), t = n.data.data ?? n.data, e = t.access_token, a = t.id_token ?? "", r = t.token_type ?? "Bearer", s = t.expires_in ?? 3600;
|
|
580
|
+
return e && await this.storeTokens({
|
|
581
|
+
accessToken: e,
|
|
582
|
+
idToken: a,
|
|
583
|
+
expiresIn: s,
|
|
584
|
+
tokenType: r
|
|
585
|
+
}), {
|
|
586
|
+
access_token: e,
|
|
587
|
+
id_token: a,
|
|
588
|
+
token_type: r,
|
|
589
|
+
expires_in: s
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* POST /auth/logout - Logout from the current device.
|
|
594
|
+
* Revokes the current token and trusted device, then clears local tokens.
|
|
595
|
+
*/
|
|
596
|
+
async logout() {
|
|
597
|
+
try {
|
|
598
|
+
const n = await this.getAccessToken(), t = {};
|
|
599
|
+
n && (t.Authorization = `Bearer ${n}`), await this.request("POST", "/auth/logout", { body: {}, headers: t }), L();
|
|
600
|
+
} catch {
|
|
601
|
+
}
|
|
602
|
+
await this.clearTokens();
|
|
603
|
+
}
|
|
604
|
+
async getAccessToken() {
|
|
605
|
+
return localStorage.getItem(P);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
export {
|
|
609
|
+
Q as AuthSDK,
|
|
610
|
+
H as AuthSDKFetchError,
|
|
611
|
+
h as arrayBufferToBase64,
|
|
612
|
+
w as arrayBufferToBase64url,
|
|
613
|
+
k as base64ToArrayBuffer,
|
|
614
|
+
Y as base64urlToArrayBuffer,
|
|
615
|
+
N as calculateThumbprint,
|
|
616
|
+
L as clearDPoPKey,
|
|
617
|
+
V as clearPasskeyEmail,
|
|
618
|
+
_ as generateDPoPKeyPair,
|
|
619
|
+
b as generateDPoPProof,
|
|
620
|
+
v as getDPoPKey,
|
|
621
|
+
j as getDPoPPublicKeyJWK,
|
|
622
|
+
G as getPasskeyEmail,
|
|
623
|
+
W as isConditionalUISupported,
|
|
624
|
+
z as isDPoPEnabled,
|
|
625
|
+
q as isWebAuthnSupported,
|
|
626
|
+
M as setPasskeyEmail,
|
|
627
|
+
X as storeDPoPKey,
|
|
628
|
+
x as stringToArrayBuffer,
|
|
629
|
+
U as toMinimalJWK,
|
|
630
|
+
F as uint8ArrayToString
|
|
631
|
+
};
|
|
632
|
+
//# sourceMappingURL=postex-auth-sdk.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postex-auth-sdk.es.js","sources":["../src/webauthn.ts","../src/auth.ts"],"sourcesContent":["export function isWebAuthnSupported(): boolean {\n return (\n typeof window !== \"undefined\" &&\n typeof window.PublicKeyCredential !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n typeof navigator.credentials !== \"undefined\"\n );\n}\n\nexport async function isConditionalUISupported(): Promise<boolean> {\n if (!isWebAuthnSupported()) return false;\n try {\n return (\n (await PublicKeyCredential.isConditionalMediationAvailable?.()) ?? false\n );\n } catch {\n return false;\n }\n}\n\nexport function arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n if (typeof base64 !== \"string\" || !base64) {\n throw new Error(\"Invalid base64: expected non-empty string\");\n }\n const cleaned = base64\n .replace(/\\s/g, \"\")\n .replace(/-/g, \"+\")\n .replace(/_/g, \"/\");\n const pad = cleaned.length % 4;\n const padded = pad > 0 ? cleaned + \"=\".repeat(4 - pad) : cleaned;\n try {\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer as ArrayBuffer;\n } catch (e) {\n throw new Error(\n \"Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.\"\n );\n }\n}\n\nexport function arrayBufferToBase64url(buffer: ArrayBuffer): string {\n const base64 = arrayBufferToBase64(buffer);\n return base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n}\n\nfunction isUUID(str: string): boolean {\n return /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(\n str\n );\n}\n\nfunction uuidToArrayBuffer(uuid: string): ArrayBuffer {\n const hex = uuid.replace(/-/g, \"\");\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\n }\n return bytes.buffer as ArrayBuffer;\n}\n\nexport function base64urlToArrayBuffer(input: string): ArrayBuffer {\n if (!input || typeof input !== \"string\") {\n throw new Error(\"Invalid input: expected non-empty string\");\n }\n // If it looks like a UUID, convert hex to bytes\n if (isUUID(input)) {\n return uuidToArrayBuffer(input);\n }\n // Otherwise treat as base64/base64url\n return base64ToArrayBuffer(input);\n}\n\nexport function stringToArrayBuffer(str: string): ArrayBuffer {\n return new TextEncoder().encode(str).buffer as ArrayBuffer;\n}\n\nexport function uint8ArrayToString(arr: Uint8Array): string {\n return String.fromCharCode(...arr);\n}\n\nconst DB_NAME = \"xpay_webauthn\";\nconst DB_VERSION = 1;\nconst STORE_NAME = \"passkey_data\";\nconst PASSKEY_EMAIL_KEY = \"passkey_email\";\n\nfunction openDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME);\n }\n };\n });\n}\n\n/**\n * Get the stored passkey email from IndexedDB\n */\nexport async function getPasskeyEmail(): Promise<string | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\nexport async function setPasskeyEmail(email: string): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(email, PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch {\n // Silently fail - passkey will still work, just won't remember email\n }\n}\n\n/**\n * Remove the passkey email from IndexedDB\n */\nexport async function clearPasskeyEmail(): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.delete(PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch {\n // Silently fail\n }\n}\n\n// ============================================================\n// DPoP (Demonstration of Proof-of-Possession) using ECDSA P-256\n// Per RFC 9449 - https://datatracker.ietf.org/doc/html/rfc9449\n// ============================================================\n\nconst DPOP_PRIVATE_KEY_STORAGE_KEY = \"dpop_private_key\";\nconst DPOP_PUBLIC_KEY_JWK_STORAGE_KEY = \"dpop_public_key_jwk\";\n\n/**\n * Minimal JWK for EC P-256 public key (only required fields per RFC 7517)\n */\nexport interface MinimalECPublicKeyJWK {\n kty: \"EC\";\n crv: \"P-256\";\n x: string;\n y: string;\n}\n\n/**\n * Create a minimal JWK from a full JWK (removes ext, key_ops, etc.)\n */\nexport function toMinimalJWK(jwk: JsonWebKey): MinimalECPublicKeyJWK {\n return {\n kty: \"EC\",\n crv: \"P-256\",\n x: jwk.x!,\n y: jwk.y!,\n };\n}\n\n/**\n * Calculate JWK Thumbprint (SHA-256) per RFC 7638\n * Uses canonical JSON with lexicographically ordered required members\n */\nexport async function calculateThumbprint(\n jwk: MinimalECPublicKeyJWK\n): Promise<string> {\n // Canonical JSON with required members in lexicographic order for EC keys\n const canonical = JSON.stringify({\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n y: jwk.y,\n });\n\n const hash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(canonical)\n );\n\n return arrayBufferToBase64url(hash);\n}\n\n/**\n * Store DPoP Private Key in IndexedDB\n */\nasync function storeDPoPPrivateKey(key: CryptoKey): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(key, DPOP_PRIVATE_KEY_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch (err) {\n console.error(\"Failed to store DPoP private key:\", err);\n }\n}\n\n/**\n * Store DPoP Public Key JWK in IndexedDB\n */\nasync function storeDPoPPublicKeyJWK(\n jwk: MinimalECPublicKeyJWK\n): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(jwk, DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch (err) {\n console.error(\"Failed to store DPoP public key JWK:\", err);\n }\n}\n\n/**\n * Retrieve DPoP Private Key from IndexedDB\n */\nexport async function getDPoPKey(): Promise<CryptoKey | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(DPOP_PRIVATE_KEY_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\n/**\n * Retrieve DPoP Public Key JWK from IndexedDB\n */\nexport async function getDPoPPublicKeyJWK(): Promise<MinimalECPublicKeyJWK | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\n/**\n * Clear stored DPoP Keys from IndexedDB\n */\nexport async function clearDPoPKey(): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n store.delete(DPOP_PRIVATE_KEY_STORAGE_KEY);\n store.delete(DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n tx.onerror = () => reject(tx.error);\n tx.oncomplete = () => {\n db.close();\n resolve();\n };\n });\n } catch {\n // Silently fail\n }\n}\n\n/**\n * Generate a new ECDSA P-256 Key Pair for DPoP.\n * Stores both Private Key (CryptoKey) and Public Key (JWK) in IndexedDB.\n * Returns minimal Public Key JWK and its Thumbprint for backend transmission.\n */\nexport async function generateDPoPKeyPair(): Promise<{\n publicKey: MinimalECPublicKeyJWK;\n thumbprint: string;\n}> {\n // 1. Generate Key Pair\n const keyPair = await crypto.subtle.generateKey(\n {\n name: \"ECDSA\",\n namedCurve: \"P-256\",\n },\n false, // Private key is non-extractable\n [\"sign\", \"verify\"]\n );\n\n // 2. Export Public Key as full JWK, then convert to minimal\n const fullJwk = await crypto.subtle.exportKey(\"jwk\", keyPair.publicKey);\n const minimalJwk = toMinimalJWK(fullJwk);\n\n // 3. Calculate Thumbprint\n const thumbprint = await calculateThumbprint(minimalJwk);\n\n // 4. Store both keys in IndexedDB\n await storeDPoPPrivateKey(keyPair.privateKey);\n await storeDPoPPublicKeyJWK(minimalJwk);\n\n return { publicKey: minimalJwk, thumbprint };\n}\n\n/**\n * Generate a DPoP proof JWT using ECDSA P-256 (ES256)\n * Per RFC 9449 Section 4.2\n *\n * @param httpMethod - HTTP method (GET, POST, etc.)\n * @param httpUri - Full URL of the request (without query/fragment for htu)\n * @param accessToken - Optional access token to bind (adds ath claim)\n */\nexport async function generateDPoPProof(\n httpMethod: string,\n httpUri: string,\n accessToken?: string\n): Promise<string | null> {\n try {\n const privateKey = await getDPoPKey();\n const publicKeyJwk = await getDPoPPublicKeyJWK();\n\n if (!privateKey || !publicKeyJwk) return null;\n\n // DPoP header per RFC 9449 Section 4.2\n // MUST include typ, alg, and jwk (public key)\n const header = {\n typ: \"dpop+jwt\",\n alg: \"ES256\",\n jwk: publicKeyJwk, // Public key in JWK format\n };\n\n // Parse URL to get htu without query/fragment\n // Use window.location.origin as base for relative URLs\n const url = new URL(\n httpUri,\n typeof window !== \"undefined\" ? window.location.origin : undefined\n );\n const htu = `${url.origin}${url.pathname}`;\n\n // DPoP payload per RFC 9449 Section 4.2\n const payload: Record<string, string | number> = {\n jti: crypto.randomUUID(),\n htm: httpMethod.toUpperCase(),\n htu: htu,\n iat: Math.floor(Date.now() / 1000),\n };\n\n if (accessToken) {\n const tokenBytes = new TextEncoder().encode(accessToken);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", tokenBytes);\n payload.ath = arrayBufferToBase64url(hashBuffer);\n }\n\n const encodedHeader = arrayBufferToBase64url(\n new TextEncoder().encode(JSON.stringify(header)).buffer as ArrayBuffer\n );\n const encodedPayload = arrayBufferToBase64url(\n new TextEncoder().encode(JSON.stringify(payload)).buffer as ArrayBuffer\n );\n\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n const signatureBuffer = await crypto.subtle.sign(\n {\n name: \"ECDSA\",\n hash: { name: \"SHA-256\" },\n },\n privateKey,\n new TextEncoder().encode(signatureInput)\n );\n const signature = arrayBufferToBase64url(signatureBuffer);\n\n return `${encodedHeader}.${encodedPayload}.${signature}`;\n } catch (err) {\n console.error(\"Failed to generate DPoP proof:\", err);\n return null;\n }\n}\n\n/**\n * Check if DPoP is enabled (Keys are stored)\n */\nexport async function isDPoPEnabled(): Promise<boolean> {\n const key = await getDPoPKey();\n return key !== null;\n}\n\n // Legacy export for backward compatibility\nexport const storeDPoPKey = storeDPoPPrivateKey;\n\nconst WebAuthn = {\n isWebAuthnSupported,\n isConditionalUISupported,\n arrayBufferToBase64,\n base64ToArrayBuffer,\n arrayBufferToBase64url,\n base64urlToArrayBuffer,\n stringToArrayBuffer,\n uint8ArrayToString,\n getPasskeyEmail,\n setPasskeyEmail,\n clearPasskeyEmail,\n toMinimalJWK,\n calculateThumbprint,\n getDPoPKey,\n getDPoPPublicKeyJWK,\n clearDPoPKey,\n generateDPoPKeyPair,\n generateDPoPProof,\n isDPoPEnabled,\n storeDPoPKey,\n};\n\n// if (typeof window !== \"undefined\") {\n// (window as unknown as { WebAuthn: typeof WebAuthn }).WebAuthn = WebAuthn;\n// }\n\n// var global: any = window || global;\n// global.WebAuthn = WebAuthn;\n// global.webauthnReady = () => {\n// document.dispatchEvent(new CustomEvent(\"webauthnReady\"));\n// };","import {\n arrayBufferToBase64,\n generateDPoPKeyPair,\n generateDPoPProof,\n stringToArrayBuffer,\n clearDPoPKey,\n base64ToArrayBuffer,\n} from \"./webauthn\";\n\ninterface AuthSDKConfig {\n apiKey?: string;\n}\n\nconst LOCALSTORAGE_TOKEN_KEY = \"postex-auth-token\";\n\ntype AuthStatusType = \"no_session\" | \"session_found\" | \"webauthn_ready\";\n\ninterface AuthStatusResponse {\n status: AuthStatusType;\n email?: string;\n webauthn?: boolean;\n challenge?: string;\n credentialIds?: string[];\n rp?: { name: string; host: string };\n}\n\n/** Response from POST /auth/initiate */\ntype InitiateAuthStatusType = \"webauthn_challenge\" | \"otp_sent\";\n\ninterface InitiateAuthResponse {\n status: InitiateAuthStatusType;\n challenge?: string;\n credentialIds?: string[];\n rp?: { name: string; host: string };\n}\n\ninterface OTPVerifyResponse {\n access_token: string;\n id_token: string;\n refresh_token: string;\n expires_in: number;\n token_type: string;\n verified: boolean;\n email: string;\n [key: string]: any;\n}\n\ninterface PasskeyRegistrationChallenge {\n challenge: string;\n rp: { name: string; id: string };\n user: { id: string; name: string; displayName: string };\n pubKeyCredParams?: Array<{ type: string; alg: number }>;\n authenticatorSelection?: AuthenticatorSelectionCriteria;\n timeout?: number;\n attestation?: AttestationConveyancePreference;\n /** Existing credential IDs to exclude (prevents duplicate registration) */\n excludeCredentials?: Array<{\n id: string;\n type: \"public-key\";\n transports?: AuthenticatorTransport[];\n }>;\n}\n\ninterface PasskeyRegisterResponse {\n registered: boolean;\n [key: string]: any;\n}\n\ninterface PasskeyStatusResponse {\n credentialId?: string;\n hasCredentials: boolean;\n [key: string]: any;\n}\n\ninterface AuthResponse {\n access_token: string;\n refresh_token: string;\n id_token?: string;\n email: string;\n name: string;\n expiresIn?: number;\n tokenType?: string;\n [key: string]: any;\n}\n\n/** Response from POST /auth/refresh */\ninterface RefreshTokenResponse {\n access_token: string;\n id_token?: string;\n token_type: string;\n expires_in: number;\n}\n\nconst DEFAULT_BASE_URL = \"http://localhost:3200\";\n\nexport class AuthSDKFetchError extends Error {\n response: { status: number; data?: any };\n\n constructor(status: number, data?: any, message?: string) {\n super(message ?? `Request failed with status ${status}`);\n this.response = { status, data };\n this.name = \"AuthSDKFetchError\";\n }\n}\n\nconst ID_TOKEN_KEY = \"auth_sdk_id_token\";\nconst REFRESH_TOKEN_KEY = \"auth_sdk_refresh_token\";\n\nexport class AuthSDK {\n private config: AuthSDKConfig;\n\n constructor(config: AuthSDKConfig) {\n this.config = config;\n }\n\n private buildUrl(path: string, params?: Record<string, string>): string {\n const base = DEFAULT_BASE_URL.replace(/\\/$/, \"\");\n const pathNorm = path.startsWith(\"/\") ? path : `/${path}`;\n const url = `${base}${pathNorm}`;\n if (!params || Object.keys(params).length === 0) return url;\n const search = new URLSearchParams(params).toString();\n return `${url}?${search}`;\n }\n\n private async request<T>(\n method: string,\n path: string,\n options?: {\n body?: any;\n params?: Record<string, string>;\n headers?: Record<string, string>;\n }\n ): Promise<{ data: T }> {\n const url = this.buildUrl(path, options?.params);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"X-API-Key\": this.config.apiKey ?? \"\",\n ...options?.headers,\n };\n\n const init: RequestInit = {\n method,\n credentials: \"include\",\n headers,\n };\n if (options?.body !== undefined && options?.body !== null) {\n init.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, init);\n\n if (!response.ok) {\n let data: any;\n try {\n const text = await response.text();\n data = text ? JSON.parse(text) : undefined;\n } catch {\n data = undefined;\n }\n if (response.status === 401) {\n await this.clearTokens();\n }\n throw new AuthSDKFetchError(response.status, data);\n }\n\n const text = await response.text();\n const data = text ? JSON.parse(text) : {};\n return { data };\n }\n\n /**\n * Returns auth headers (Authorization + DPoP) for the given request.\n * Use this to attach auth to your own HTTP client (e.g. axios request interceptor).\n * @param method - HTTP method (e.g. \"GET\", \"POST\")\n * @param url - Full request URL\n */\n async getRequestAuthHeaders(\n method: string,\n url: string\n ): Promise<Record<string, string>> {\n const token = localStorage.getItem(LOCALSTORAGE_TOKEN_KEY);\n if (!token) return {};\n const fullUrl = url.startsWith(\"http\") ? url : `${DEFAULT_BASE_URL}${url}`;\n const dpopProof = await generateDPoPProof(\n method.toUpperCase(),\n fullUrl,\n token\n );\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n if (dpopProof) headers[\"DPoP\"] = dpopProof;\n return headers;\n }\n\n /**\n * GET /auth/status - Check if client has trusted device session and what auth method is available.\n * Returns no_session | session_found | webauthn_ready per PostEx Auth BFF spec.\n */\n async getStatus(email: string): Promise<AuthStatusResponse> {\n const response = await this.request<unknown>(\"GET\", \"/auth/status\", {\n params: { email },\n });\n return (response.data as any).data ?? response.data;\n }\n\n /**\n * POST /auth/initiate - Unified entry: returns webauthn_challenge or otp_sent.\n * Sets auth_session cookie when otp_sent.\n */\n async initiateAuth(email: string): Promise<InitiateAuthResponse> {\n const response = await this.request<unknown>(\"POST\", \"/auth/initiate\", {\n body: { email },\n });\n const data = (response.data as any).data ?? response.data;\n return {\n status: data.status,\n challenge: data.challenge,\n credentialIds: data.credentialIds,\n rp: data.rp,\n };\n }\n\n /**\n * POST /otp/verify - Verifies the OTP code entered by the user.\n * Stores tokens from the response.\n */\n async verifyOTP(otp: string): Promise<OTPVerifyResponse> {\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/otp/verify`\n );\n\n const response = await this.request<unknown>(\"POST\", \"/otp/verify\", {\n body: { otp },\n headers: dpopProof ? { DPoP: dpopProof } : {},\n });\n const data = (response.data as any).data ?? response.data;\n\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.access_token ?? result.accessToken ?? result.AccessToken;\n const refreshToken =\n result.refresh_token ?? result.refreshToken ?? result.RefreshToken;\n const idToken = result.id_token ?? result.idToken ?? result.IdToken;\n const expiresIn =\n result.expires_in ?? result.expiresIn ?? result.ExpiresIn ?? 3600;\n const tokenType =\n result.token_type ?? result.tokenType ?? result.TokenType ?? \"Bearer\";\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: expiresIn ?? 3600,\n tokenType: tokenType ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken ?? \"\",\n expires_in: expiresIn,\n token_type: tokenType,\n verified: result.verified ?? result.Verified ?? true,\n email: result.email ?? result.Email ?? \"\",\n ...result,\n };\n }\n\n /**\n * GET /magic-link - Verify a magic link token.\n * Sets auth_session cookie on success.\n */\n async verifyMagicLink(token: string, email: string): Promise<void> {\n await this.request(\"GET\", \"/verify/magic-link\", {\n params: { token, email, redirect_mode: \"frontend\" },\n });\n }\n\n /**\n * POST /magic-link/complete - Complete magic link authentication.\n * Requires auth_session cookie set by verifyMagicLink.\n * Stores tokens from the response.\n */\n async completeMagicLink(): Promise<OTPVerifyResponse> {\n const response = await this.request<unknown>(\n \"POST\",\n \"/verify/magic-link/complete\",\n {\n body: {},\n }\n );\n const data = (response.data as any).data ?? response.data;\n\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.access_token ?? result.accessToken ?? result.AccessToken;\n const refreshToken =\n result.refresh_token ?? result.refreshToken ?? result.RefreshToken;\n const idToken = result.id_token ?? result.idToken ?? result.IdToken;\n const expiresIn =\n result.expires_in ?? result.expiresIn ?? result.ExpiresIn ?? 3600;\n const tokenType =\n result.token_type ?? result.tokenType ?? result.TokenType ?? \"Bearer\";\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: expiresIn ?? 3600,\n tokenType: tokenType ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken ?? \"\",\n expires_in: expiresIn,\n token_type: tokenType,\n verified: result.verified ?? result.Verified ?? true,\n email: result.email ?? result.Email ?? \"\",\n ...result,\n };\n }\n\n async initiatePasskeyRegistration(): Promise<PasskeyRegistrationChallenge> {\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/initiate/challenge\",\n {\n body: {},\n }\n );\n return (response.data as any).data ?? response.data;\n }\n\n async registerPasskey(email: string): Promise<PasskeyRegisterResponse> {\n const challenge = await this.initiatePasskeyRegistration();\n let userIdBuffer: ArrayBuffer;\n if (challenge?.user?.id) {\n try {\n userIdBuffer = base64ToArrayBuffer(challenge.user.id);\n } catch {\n userIdBuffer = stringToArrayBuffer(challenge.user.id);\n }\n } else {\n userIdBuffer = stringToArrayBuffer(email);\n }\n\n const pubKeyCredParams = (\n challenge.pubKeyCredParams ?? [\n { type: \"public-key\", alg: -7 },\n { type: \"public-key\", alg: -257 },\n ]\n ).map((param) => ({\n type: \"public-key\" as const,\n alg: param.alg,\n }));\n\n const excludeCredentials: PublicKeyCredentialDescriptor[] | undefined =\n challenge.excludeCredentials?.map((cred) => ({\n type: \"public-key\" as const,\n id: base64ToArrayBuffer(cred.id),\n transports: cred.transports,\n }));\n\n const createOptions: PublicKeyCredentialCreationOptions = {\n challenge: base64ToArrayBuffer(challenge.challenge),\n rp: {\n name: challenge.rp?.name ?? \"XPay\",\n id: challenge.rp?.id ?? window.location.hostname,\n },\n user: {\n id: userIdBuffer,\n name: challenge.user?.name ?? email,\n displayName: challenge.user?.displayName ?? email,\n },\n pubKeyCredParams,\n timeout: challenge.timeout ?? 60000,\n attestation: challenge.attestation ?? \"none\",\n authenticatorSelection: challenge.authenticatorSelection ?? {\n residentKey: \"required\",\n userVerification: \"required\",\n },\n };\n\n const credential = (await navigator.credentials.create({\n publicKey: createOptions,\n })) as PublicKeyCredential;\n\n if (!credential) throw new Error(\"Credential creation failed\");\n const attResp = credential.response as AuthenticatorAttestationResponse;\n const payload = {\n clientDataJSON: arrayBufferToBase64(attResp.clientDataJSON),\n attestationObject: arrayBufferToBase64(attResp.attestationObject),\n rawId: arrayBufferToBase64(credential.rawId as ArrayBuffer),\n }; \n if (!payload.rawId) throw new Error(\"Raw ID is required\");\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/webauthn/register/challenge`\n );\n\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/register/challenge\",\n {\n body: payload,\n headers: dpopProof ? { DPoP: dpopProof } : {},\n }\n );\n\n return (response.data as any).data ?? response.data;\n }\n\n /**\n * POST /webauthn/authenticate/challenge - Authenticate with passkey.\n */\n async authenticateWithPasskey({\n challenge,\n rp,\n credentialIds,\n }: {\n challenge: string;\n rp: { name: string; host: string };\n credentialIds: string[];\n }): Promise<AuthResponse> {\n const assertion = (await navigator.credentials.get({\n publicKey: {\n challenge: base64ToArrayBuffer(challenge),\n rpId: rp?.host ?? undefined,\n allowCredentials: credentialIds.map((id: string) => ({\n type: \"public-key\" as const,\n id: base64ToArrayBuffer(id),\n // Hint browser about possible transports for faster authenticator discovery\n // transports: [\"internal\", \"hybrid\"] as AuthenticatorTransport[],\n })),\n timeout: 60000,\n userVerification: \"required\",\n },\n })) as PublicKeyCredential;\n\n if (!assertion) throw new Error(\"Authentication failed\");\n const assertionResponse =\n assertion.response as AuthenticatorAssertionResponse;\n const payload = {\n clientDataJSON: arrayBufferToBase64(assertionResponse.clientDataJSON),\n authenticatorData: arrayBufferToBase64(\n assertionResponse.authenticatorData\n ),\n signature: arrayBufferToBase64(assertionResponse.signature),\n rawId: arrayBufferToBase64(assertion.rawId as ArrayBuffer),\n userHandle: assertionResponse.userHandle\n ? arrayBufferToBase64(assertionResponse.userHandle)\n : \"\",\n };\n\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/webauthn/authenticate/challenge`\n );\n\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/authenticate/challenge\",\n {\n body: payload,\n headers: dpopProof ? { DPoP: dpopProof } : {},\n }\n );\n\n const data = (response.data as any).data ?? response.data;\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.AccessToken ?? result.accessToken ?? result.access_token;\n const refreshToken =\n result.RefreshToken ?? result.refreshToken ?? result.refresh_token;\n const idToken = result.IdToken ?? result.idToken ?? result.id_token;\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: result.expiresIn ?? result.ExpiresIn ?? 3600,\n tokenType: result.tokenType ?? result.token_type ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken,\n email: result.email,\n name: result.name ?? result.userName,\n expiresIn: result.expiresIn ?? result.ExpiresIn,\n tokenType: result.tokenType ?? result.token_type,\n ...result,\n };\n }\n /**\n * GET /webauthn/credentials/:username - Get user's passkey status.\n */\n async getPasskeyStatus(username: string): Promise<PasskeyStatusResponse> {\n const encoded = encodeURIComponent(username);\n const path = `/webauthn/credentials/${encoded}`;\n const signed = await this.signRequest(\"GET\", path);\n const response = await this.request<unknown>(\"GET\", path, {\n headers: signed.headers as Record<string, string>,\n });\n const data = (response.data as any).data ?? response.data;\n return {\n ...data,\n hasCredentials: Boolean(data.hasCredentials ?? data.credentialId),\n };\n }\n\n /**\n * DELETE /webauthn/credentials/:username - Remove passkey.\n */\n async removePasskey(username: string): Promise<void> {\n const encoded = encodeURIComponent(username);\n const path = `/webauthn/credentials/${encoded}`;\n const signed = await this.signRequest(\"DELETE\", path);\n await this.request(\"DELETE\", path, {\n headers: signed.headers as Record<string, string>,\n });\n }\n\n /**\n * Signs a request with DPoP and Authorization headers (internal use).\n */\n async signRequest(\n method: string,\n url: string,\n config: any = {}\n ): Promise<any> {\n const fullUrl = url.startsWith(\"http\") ? url : `${DEFAULT_BASE_URL}${url}`;\n const authHeaders = await this.getRequestAuthHeaders(method, fullUrl);\n return { ...config, headers: { ...config.headers, ...authHeaders } };\n }\n\n /**\n * Replaces native fetch or Axios with a DPoP-signed version.\n */\n async authenticatedFetch(\n input: RequestInfo | URL,\n init?: RequestInit\n ): Promise<Response> {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n const method = init?.method || \"GET\";\n\n const signedInit = await this.signRequest(method, url, {\n headers: init?.headers,\n });\n return fetch(input, { ...init, headers: signedInit.headers });\n }\n\n /**\n * Store tokens from /webauthn/authenticate (per spec: sessionStorage preferred).\n */\n async storeTokens(tokens: {\n accessToken: string;\n refreshToken?: string;\n idToken?: string;\n expiresIn?: number;\n tokenType?: string;\n }): Promise<void> {\n localStorage.setItem(LOCALSTORAGE_TOKEN_KEY, tokens.accessToken);\n if (tokens.refreshToken) {\n localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken);\n }\n if (tokens.idToken) {\n localStorage.setItem(ID_TOKEN_KEY, tokens.idToken);\n }\n }\n\n /**\n * Clear stored tokens (call on logout).\n */\n async clearTokens(): Promise<void> {\n localStorage.removeItem(LOCALSTORAGE_TOKEN_KEY);\n localStorage.removeItem(ID_TOKEN_KEY);\n localStorage.removeItem(REFRESH_TOKEN_KEY);\n }\n\n /**\n * POST /auth/refresh - Refresh access token using server-stored refresh token.\n * Requires trusted device cookie (td). Refresh token is stored server-side.\n * Rate limit: 10 requests per minute.\n */\n async refreshToken(): Promise<RefreshTokenResponse> {\n const response = await this.request<unknown>(\"POST\", \"/auth/refresh\", {\n body: {},\n });\n const data = (response.data as any).data ?? response.data;\n\n const accessToken = data.access_token;\n const idToken = data.id_token ?? \"\";\n const tokenType = data.token_type ?? \"Bearer\";\n const expiresIn = data.expires_in ?? 3600;\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n idToken,\n expiresIn,\n tokenType,\n });\n }\n\n return {\n access_token: accessToken,\n id_token: idToken,\n token_type: tokenType,\n expires_in: expiresIn,\n };\n }\n\n /**\n * POST /auth/logout - Logout from the current device.\n * Revokes the current token and trusted device, then clears local tokens.\n */\n async logout(): Promise<void> {\n try {\n const token = await this.getAccessToken();\n const headers: Record<string, string> = {};\n if (token) {\n headers[\"Authorization\"] = `Bearer ${token}`;\n }\n await this.request(\"POST\", \"/auth/logout\", { body: {}, headers });\n clearDPoPKey();\n } catch {\n // Silently fail - proceed with local cleanup\n }\n await this.clearTokens();\n }\n\n async getAccessToken(): Promise<string | null> {\n return localStorage.getItem(LOCALSTORAGE_TOKEN_KEY);\n }\n}\n\n// Expose SDK on global window for use by other JS projects (e.g. script tag / iframe)\n// if (typeof window !== \"undefined\") {\n// (window as unknown as { AuthSDK: typeof AuthSDK }).AuthSDK = AuthSDK;\n// }\n\n// var global: any = window || global;\n// global.AuthSDK = AuthSDK;\n// global.authsdkReady = () => {\n// document.dispatchEvent(new CustomEvent(\"authsdkReady\"));\n// };\n"],"names":["isWebAuthnSupported","isConditionalUISupported","arrayBufferToBase64","buffer","bytes","binary","i","base64ToArrayBuffer","base64","cleaned","pad","padded","arrayBufferToBase64url","isUUID","str","uuidToArrayBuffer","uuid","hex","base64urlToArrayBuffer","input","stringToArrayBuffer","uint8ArrayToString","arr","DB_NAME","DB_VERSION","STORE_NAME","PASSKEY_EMAIL_KEY","openDB","resolve","reject","request","db","getPasskeyEmail","tx","setPasskeyEmail","email","clearPasskeyEmail","DPOP_PRIVATE_KEY_STORAGE_KEY","DPOP_PUBLIC_KEY_JWK_STORAGE_KEY","toMinimalJWK","jwk","calculateThumbprint","canonical","hash","storeDPoPPrivateKey","key","err","storeDPoPPublicKeyJWK","getDPoPKey","getDPoPPublicKeyJWK","clearDPoPKey","store","generateDPoPKeyPair","keyPair","fullJwk","minimalJwk","thumbprint","generateDPoPProof","httpMethod","httpUri","accessToken","privateKey","publicKeyJwk","header","url","htu","payload","tokenBytes","hashBuffer","encodedHeader","encodedPayload","signatureInput","signatureBuffer","signature","isDPoPEnabled","storeDPoPKey","LOCALSTORAGE_TOKEN_KEY","DEFAULT_BASE_URL","AuthSDKFetchError","status","data","message","ID_TOKEN_KEY","REFRESH_TOKEN_KEY","AuthSDK","config","path","params","base","pathNorm","search","method","options","headers","init","response","text","token","fullUrl","dpopProof","otp","result","refreshToken","idToken","expiresIn","tokenType","challenge","userIdBuffer","pubKeyCredParams","param","cred","createOptions","credential","attResp","rp","credentialIds","assertion","id","assertionResponse","username","signed","authHeaders","signedInit","tokens"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var PostexAuthSDK=(function(i){"use strict";function v(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function N(){if(!v())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function f(a){const n=new Uint8Array(a);let t="";for(let e=0;e<n.byteLength;e++)t+=String.fromCharCode(n[e]);return btoa(t)}function k(a){if(typeof a!="string"||!a)throw new Error("Invalid base64: expected non-empty string");const n=a.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),t=n.length%4,e=t>0?n+"=".repeat(4-t):n;try{const o=atob(e),r=new Uint8Array(o.length);for(let s=0;s<o.length;s++)r[s]=o.charCodeAt(s);return r.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function w(a){return f(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function J(a){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(a)}function j(a){const n=a.replace(/-/g,""),t=new Uint8Array(n.length/2);for(let e=0;e<t.length;e++)t[e]=parseInt(n.substr(e*2,2),16);return t.buffer}function L(a){if(!a||typeof a!="string")throw new Error("Invalid input: expected non-empty string");return J(a)?j(a):k(a)}function _(a){return new TextEncoder().encode(a).buffer}function W(a){return String.fromCharCode(...a)}const H="xpay_webauthn",M=1,d="passkey_data",E="passkey_email";function p(){return new Promise((a,n)=>{const t=indexedDB.open(H,M);t.onerror=()=>n(t.error),t.onsuccess=()=>a(t.result),t.onupgradeneeded=()=>{const e=t.result;e.objectStoreNames.contains(d)||e.createObjectStore(d)}})}async function F(){try{const a=await p();return new Promise((n,t)=>{const e=a.transaction(d,"readonly"),r=e.objectStore(d).get(E);r.onerror=()=>t(r.error),r.onsuccess=()=>n(r.result??null),e.oncomplete=()=>a.close()})}catch{return null}}async function Y(a){try{const n=await p();return new Promise((t,e)=>{const o=n.transaction(d,"readwrite"),s=o.objectStore(d).put(a,E);s.onerror=()=>e(s.error),s.onsuccess=()=>t(),o.oncomplete=()=>n.close()})}catch{}}async function G(){try{const a=await p();return new Promise((n,t)=>{const e=a.transaction(d,"readwrite"),r=e.objectStore(d).delete(E);r.onerror=()=>t(r.error),r.onsuccess=()=>n(),e.oncomplete=()=>a.close()})}catch{}}const I="dpop_private_key",A="dpop_public_key_jwk";function O(a){return{kty:"EC",crv:"P-256",x:a.x,y:a.y}}async function B(a){const n=JSON.stringify({crv:a.crv,kty:a.kty,x:a.x,y:a.y}),t=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(n));return w(t)}async function q(a){try{const n=await p();return new Promise((t,e)=>{const o=n.transaction(d,"readwrite"),s=o.objectStore(d).put(a,I);s.onerror=()=>e(s.error),s.onsuccess=()=>t(),o.oncomplete=()=>n.close()})}catch(n){console.error("Failed to store DPoP private key:",n)}}async function V(a){try{const n=await p();return new Promise((t,e)=>{const o=n.transaction(d,"readwrite"),s=o.objectStore(d).put(a,A);s.onerror=()=>e(s.error),s.onsuccess=()=>t(),o.oncomplete=()=>n.close()})}catch(n){console.error("Failed to store DPoP public key JWK:",n)}}async function K(){try{const a=await p();return new Promise((n,t)=>{const e=a.transaction(d,"readonly"),r=e.objectStore(d).get(I);r.onerror=()=>t(r.error),r.onsuccess=()=>n(r.result??null),e.oncomplete=()=>a.close()})}catch{return null}}async function R(){try{const a=await p();return new Promise((n,t)=>{const e=a.transaction(d,"readonly"),r=e.objectStore(d).get(A);r.onerror=()=>t(r.error),r.onsuccess=()=>n(r.result??null),e.oncomplete=()=>a.close()})}catch{return null}}async function x(){try{const a=await p();return new Promise((n,t)=>{const e=a.transaction(d,"readwrite"),o=e.objectStore(d);o.delete(I),o.delete(A),e.onerror=()=>t(e.error),e.oncomplete=()=>{a.close(),n()}})}catch{}}async function P(){const a=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),n=await crypto.subtle.exportKey("jwk",a.publicKey),t=O(n),e=await B(t);return await q(a.privateKey),await V(t),{publicKey:t,thumbprint:e}}async function T(a,n,t){try{const e=await K(),o=await R();if(!e||!o)return null;const r={typ:"dpop+jwt",alg:"ES256",jwk:o},s=new URL(n,typeof window<"u"?window.location.origin:void 0),u=`${s.origin}${s.pathname}`,l={jti:crypto.randomUUID(),htm:a.toUpperCase(),htu:u,iat:Math.floor(Date.now()/1e3)};if(t){const D=new TextEncoder().encode(t),Z=await crypto.subtle.digest("SHA-256",D);l.ath=w(Z)}const h=w(new TextEncoder().encode(JSON.stringify(r)).buffer),c=w(new TextEncoder().encode(JSON.stringify(l)).buffer),y=`${h}.${c}`,m=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},e,new TextEncoder().encode(y)),S=w(m);return`${h}.${c}.${S}`}catch(e){return console.error("Failed to generate DPoP proof:",e),null}}async function z(){return await K()!==null}const X=q,b="postex-auth-token",g="http://localhost:3200";class C extends Error{constructor(n,t,e){super(e??`Request failed with status ${n}`),this.response={status:n,data:t},this.name="AuthSDKFetchError"}}const $="auth_sdk_id_token",U="auth_sdk_refresh_token";class Q{constructor(n){this.config=n}buildUrl(n,t){const e=g.replace(/\/$/,""),o=n.startsWith("/")?n:`/${n}`,r=`${e}${o}`;if(!t||Object.keys(t).length===0)return r;const s=new URLSearchParams(t).toString();return`${r}?${s}`}async request(n,t,e){const o=this.buildUrl(t,e?.params),r={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...e?.headers},s={method:n,credentials:"include",headers:r};e?.body!==void 0&&e?.body!==null&&(s.body=JSON.stringify(e.body));const u=await fetch(o,s);if(!u.ok){let c;try{const y=await u.text();c=y?JSON.parse(y):void 0}catch{c=void 0}throw u.status===401&&await this.clearTokens(),new C(u.status,c)}const l=await u.text();return{data:l?JSON.parse(l):{}}}async getRequestAuthHeaders(n,t){const e=localStorage.getItem(b);if(!e)return{};const o=t.startsWith("http")?t:`${g}${t}`,r=await T(n.toUpperCase(),o,e),s={Authorization:`Bearer ${e}`};return r&&(s.DPoP=r),s}async getStatus(n){const t=await this.request("GET","/auth/status",{params:{email:n}});return t.data.data??t.data}async initiateAuth(n){const t=await this.request("POST","/auth/initiate",{body:{email:n}}),e=t.data.data??t.data;return{status:e.status,challenge:e.challenge,credentialIds:e.credentialIds,rp:e.rp}}async verifyOTP(n){await P();const t=await T("POST",`${g}/otp/verify`),e=await this.request("POST","/otp/verify",{body:{otp:n},headers:t?{DPoP:t}:{}}),o=e.data.data??e.data,r=o.AuthenticationResult??o,s=r.access_token??r.accessToken??r.AccessToken,u=r.refresh_token??r.refreshToken??r.RefreshToken,l=r.id_token??r.idToken??r.IdToken,h=r.expires_in??r.expiresIn??r.ExpiresIn??3600,c=r.token_type??r.tokenType??r.TokenType??"Bearer";return s&&await this.storeTokens({accessToken:s,refreshToken:u??"",idToken:l??"",expiresIn:h??3600,tokenType:c??"Bearer"}),{access_token:s,refresh_token:u??"",id_token:l??"",expires_in:h,token_type:c,verified:r.verified??r.Verified??!0,email:r.email??r.Email??"",...r}}async verifyMagicLink(n,t){await this.request("GET","/verify/magic-link",{params:{token:n,email:t,redirect_mode:"frontend"}})}async completeMagicLink(){const n=await this.request("POST","/verify/magic-link/complete",{body:{}}),t=n.data.data??n.data,e=t.AuthenticationResult??t,o=e.access_token??e.accessToken??e.AccessToken,r=e.refresh_token??e.refreshToken??e.RefreshToken,s=e.id_token??e.idToken??e.IdToken,u=e.expires_in??e.expiresIn??e.ExpiresIn??3600,l=e.token_type??e.tokenType??e.TokenType??"Bearer";return o&&await this.storeTokens({accessToken:o,refreshToken:r??"",idToken:s??"",expiresIn:u??3600,tokenType:l??"Bearer"}),{access_token:o,refresh_token:r??"",id_token:s??"",expires_in:u,token_type:l,verified:e.verified??e.Verified??!0,email:e.email??e.Email??"",...e}}async initiatePasskeyRegistration(){const n=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return n.data.data??n.data}async registerPasskey(n){const t=await this.initiatePasskeyRegistration();let e;if(t?.user?.id)try{e=k(t.user.id)}catch{e=_(t.user.id)}else e=_(n);const o=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(y=>({type:"public-key",alg:y.alg}));t.excludeCredentials?.map(y=>({type:"public-key",id:k(y.id),transports:y.transports}));const r={challenge:k(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:e,name:t.user?.name??n,displayName:t.user?.displayName??n},pubKeyCredParams:o,timeout:t.timeout??6e4,attestation:t.attestation??"none",authenticatorSelection:t.authenticatorSelection??{residentKey:"required",userVerification:"required"}},s=await navigator.credentials.create({publicKey:r});if(!s)throw new Error("Credential creation failed");const u=s.response,l={clientDataJSON:f(u.clientDataJSON),attestationObject:f(u.attestationObject),rawId:f(s.rawId)};if(!l.rawId)throw new Error("Raw ID is required");await P();const h=await T("POST",`${g}/webauthn/register/challenge`),c=await this.request("POST","/webauthn/register/challenge",{body:l,headers:h?{DPoP:h}:{}});return c.data.data??c.data}async authenticateWithPasskey({challenge:n,rp:t,credentialIds:e}){const o=await navigator.credentials.get({publicKey:{challenge:k(n),rpId:t?.host??void 0,allowCredentials:e.map(D=>({type:"public-key",id:k(D)})),timeout:6e4,userVerification:"required"}});if(!o)throw new Error("Authentication failed");const r=o.response,s={clientDataJSON:f(r.clientDataJSON),authenticatorData:f(r.authenticatorData),signature:f(r.signature),rawId:f(o.rawId),userHandle:r.userHandle?f(r.userHandle):""};await P();const u=await T("POST",`${g}/webauthn/authenticate/challenge`),l=await this.request("POST","/webauthn/authenticate/challenge",{body:s,headers:u?{DPoP:u}:{}}),h=l.data.data??l.data,c=h.AuthenticationResult??h,y=c.AccessToken??c.accessToken??c.access_token,m=c.RefreshToken??c.refreshToken??c.refresh_token,S=c.IdToken??c.idToken??c.id_token;return y&&await this.storeTokens({accessToken:y,refreshToken:m??"",idToken:S??"",expiresIn:c.expiresIn??c.ExpiresIn??3600,tokenType:c.tokenType??c.token_type??"Bearer"}),{access_token:y,refresh_token:m??"",id_token:S,email:c.email,name:c.name??c.userName,expiresIn:c.expiresIn??c.ExpiresIn,tokenType:c.tokenType??c.token_type,...c}}async getPasskeyStatus(n){const e=`/webauthn/credentials/${encodeURIComponent(n)}`,o=await this.signRequest("GET",e),r=await this.request("GET",e,{headers:o.headers}),s=r.data.data??r.data;return{...s,hasCredentials:!!(s.hasCredentials??s.credentialId)}}async removePasskey(n){const e=`/webauthn/credentials/${encodeURIComponent(n)}`,o=await this.signRequest("DELETE",e);await this.request("DELETE",e,{headers:o.headers})}async signRequest(n,t,e={}){const o=t.startsWith("http")?t:`${g}${t}`,r=await this.getRequestAuthHeaders(n,o);return{...e,headers:{...e.headers,...r}}}async authenticatedFetch(n,t){const e=typeof n=="string"?n:n instanceof URL?n.toString():n.url,o=t?.method||"GET",r=await this.signRequest(o,e,{headers:t?.headers});return fetch(n,{...t,headers:r.headers})}async storeTokens(n){localStorage.setItem(b,n.accessToken),n.refreshToken&&localStorage.setItem(U,n.refreshToken),n.idToken&&localStorage.setItem($,n.idToken)}async clearTokens(){localStorage.removeItem(b),localStorage.removeItem($),localStorage.removeItem(U)}async refreshToken(){const n=await this.request("POST","/auth/refresh",{body:{}}),t=n.data.data??n.data,e=t.access_token,o=t.id_token??"",r=t.token_type??"Bearer",s=t.expires_in??3600;return e&&await this.storeTokens({accessToken:e,idToken:o,expiresIn:s,tokenType:r}),{access_token:e,id_token:o,token_type:r,expires_in:s}}async logout(){try{const n=await this.getAccessToken(),t={};n&&(t.Authorization=`Bearer ${n}`),await this.request("POST","/auth/logout",{body:{},headers:t}),x()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(b)}}return i.AuthSDK=Q,i.AuthSDKFetchError=C,i.arrayBufferToBase64=f,i.arrayBufferToBase64url=w,i.base64ToArrayBuffer=k,i.base64urlToArrayBuffer=L,i.calculateThumbprint=B,i.clearDPoPKey=x,i.clearPasskeyEmail=G,i.generateDPoPKeyPair=P,i.generateDPoPProof=T,i.getDPoPKey=K,i.getDPoPPublicKeyJWK=R,i.getPasskeyEmail=F,i.isConditionalUISupported=N,i.isDPoPEnabled=z,i.isWebAuthnSupported=v,i.setPasskeyEmail=Y,i.storeDPoPKey=X,i.stringToArrayBuffer=_,i.toMinimalJWK=O,i.uint8ArrayToString=W,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"}),i})({});
|
|
2
|
+
//# sourceMappingURL=postex-auth-sdk.iife.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postex-auth-sdk.iife.js","sources":["../src/webauthn.ts","../src/auth.ts"],"sourcesContent":["export function isWebAuthnSupported(): boolean {\n return (\n typeof window !== \"undefined\" &&\n typeof window.PublicKeyCredential !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n typeof navigator.credentials !== \"undefined\"\n );\n}\n\nexport async function isConditionalUISupported(): Promise<boolean> {\n if (!isWebAuthnSupported()) return false;\n try {\n return (\n (await PublicKeyCredential.isConditionalMediationAvailable?.()) ?? false\n );\n } catch {\n return false;\n }\n}\n\nexport function arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n if (typeof base64 !== \"string\" || !base64) {\n throw new Error(\"Invalid base64: expected non-empty string\");\n }\n const cleaned = base64\n .replace(/\\s/g, \"\")\n .replace(/-/g, \"+\")\n .replace(/_/g, \"/\");\n const pad = cleaned.length % 4;\n const padded = pad > 0 ? cleaned + \"=\".repeat(4 - pad) : cleaned;\n try {\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer as ArrayBuffer;\n } catch (e) {\n throw new Error(\n \"Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.\"\n );\n }\n}\n\nexport function arrayBufferToBase64url(buffer: ArrayBuffer): string {\n const base64 = arrayBufferToBase64(buffer);\n return base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n}\n\nfunction isUUID(str: string): boolean {\n return /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(\n str\n );\n}\n\nfunction uuidToArrayBuffer(uuid: string): ArrayBuffer {\n const hex = uuid.replace(/-/g, \"\");\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\n }\n return bytes.buffer as ArrayBuffer;\n}\n\nexport function base64urlToArrayBuffer(input: string): ArrayBuffer {\n if (!input || typeof input !== \"string\") {\n throw new Error(\"Invalid input: expected non-empty string\");\n }\n // If it looks like a UUID, convert hex to bytes\n if (isUUID(input)) {\n return uuidToArrayBuffer(input);\n }\n // Otherwise treat as base64/base64url\n return base64ToArrayBuffer(input);\n}\n\nexport function stringToArrayBuffer(str: string): ArrayBuffer {\n return new TextEncoder().encode(str).buffer as ArrayBuffer;\n}\n\nexport function uint8ArrayToString(arr: Uint8Array): string {\n return String.fromCharCode(...arr);\n}\n\nconst DB_NAME = \"xpay_webauthn\";\nconst DB_VERSION = 1;\nconst STORE_NAME = \"passkey_data\";\nconst PASSKEY_EMAIL_KEY = \"passkey_email\";\n\nfunction openDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME);\n }\n };\n });\n}\n\n/**\n * Get the stored passkey email from IndexedDB\n */\nexport async function getPasskeyEmail(): Promise<string | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\nexport async function setPasskeyEmail(email: string): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(email, PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch {\n // Silently fail - passkey will still work, just won't remember email\n }\n}\n\n/**\n * Remove the passkey email from IndexedDB\n */\nexport async function clearPasskeyEmail(): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.delete(PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch {\n // Silently fail\n }\n}\n\n// ============================================================\n// DPoP (Demonstration of Proof-of-Possession) using ECDSA P-256\n// Per RFC 9449 - https://datatracker.ietf.org/doc/html/rfc9449\n// ============================================================\n\nconst DPOP_PRIVATE_KEY_STORAGE_KEY = \"dpop_private_key\";\nconst DPOP_PUBLIC_KEY_JWK_STORAGE_KEY = \"dpop_public_key_jwk\";\n\n/**\n * Minimal JWK for EC P-256 public key (only required fields per RFC 7517)\n */\nexport interface MinimalECPublicKeyJWK {\n kty: \"EC\";\n crv: \"P-256\";\n x: string;\n y: string;\n}\n\n/**\n * Create a minimal JWK from a full JWK (removes ext, key_ops, etc.)\n */\nexport function toMinimalJWK(jwk: JsonWebKey): MinimalECPublicKeyJWK {\n return {\n kty: \"EC\",\n crv: \"P-256\",\n x: jwk.x!,\n y: jwk.y!,\n };\n}\n\n/**\n * Calculate JWK Thumbprint (SHA-256) per RFC 7638\n * Uses canonical JSON with lexicographically ordered required members\n */\nexport async function calculateThumbprint(\n jwk: MinimalECPublicKeyJWK\n): Promise<string> {\n // Canonical JSON with required members in lexicographic order for EC keys\n const canonical = JSON.stringify({\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n y: jwk.y,\n });\n\n const hash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(canonical)\n );\n\n return arrayBufferToBase64url(hash);\n}\n\n/**\n * Store DPoP Private Key in IndexedDB\n */\nasync function storeDPoPPrivateKey(key: CryptoKey): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(key, DPOP_PRIVATE_KEY_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch (err) {\n console.error(\"Failed to store DPoP private key:\", err);\n }\n}\n\n/**\n * Store DPoP Public Key JWK in IndexedDB\n */\nasync function storeDPoPPublicKeyJWK(\n jwk: MinimalECPublicKeyJWK\n): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(jwk, DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch (err) {\n console.error(\"Failed to store DPoP public key JWK:\", err);\n }\n}\n\n/**\n * Retrieve DPoP Private Key from IndexedDB\n */\nexport async function getDPoPKey(): Promise<CryptoKey | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(DPOP_PRIVATE_KEY_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\n/**\n * Retrieve DPoP Public Key JWK from IndexedDB\n */\nexport async function getDPoPPublicKeyJWK(): Promise<MinimalECPublicKeyJWK | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\n/**\n * Clear stored DPoP Keys from IndexedDB\n */\nexport async function clearDPoPKey(): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n store.delete(DPOP_PRIVATE_KEY_STORAGE_KEY);\n store.delete(DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n tx.onerror = () => reject(tx.error);\n tx.oncomplete = () => {\n db.close();\n resolve();\n };\n });\n } catch {\n // Silently fail\n }\n}\n\n/**\n * Generate a new ECDSA P-256 Key Pair for DPoP.\n * Stores both Private Key (CryptoKey) and Public Key (JWK) in IndexedDB.\n * Returns minimal Public Key JWK and its Thumbprint for backend transmission.\n */\nexport async function generateDPoPKeyPair(): Promise<{\n publicKey: MinimalECPublicKeyJWK;\n thumbprint: string;\n}> {\n // 1. Generate Key Pair\n const keyPair = await crypto.subtle.generateKey(\n {\n name: \"ECDSA\",\n namedCurve: \"P-256\",\n },\n false, // Private key is non-extractable\n [\"sign\", \"verify\"]\n );\n\n // 2. Export Public Key as full JWK, then convert to minimal\n const fullJwk = await crypto.subtle.exportKey(\"jwk\", keyPair.publicKey);\n const minimalJwk = toMinimalJWK(fullJwk);\n\n // 3. Calculate Thumbprint\n const thumbprint = await calculateThumbprint(minimalJwk);\n\n // 4. Store both keys in IndexedDB\n await storeDPoPPrivateKey(keyPair.privateKey);\n await storeDPoPPublicKeyJWK(minimalJwk);\n\n return { publicKey: minimalJwk, thumbprint };\n}\n\n/**\n * Generate a DPoP proof JWT using ECDSA P-256 (ES256)\n * Per RFC 9449 Section 4.2\n *\n * @param httpMethod - HTTP method (GET, POST, etc.)\n * @param httpUri - Full URL of the request (without query/fragment for htu)\n * @param accessToken - Optional access token to bind (adds ath claim)\n */\nexport async function generateDPoPProof(\n httpMethod: string,\n httpUri: string,\n accessToken?: string\n): Promise<string | null> {\n try {\n const privateKey = await getDPoPKey();\n const publicKeyJwk = await getDPoPPublicKeyJWK();\n\n if (!privateKey || !publicKeyJwk) return null;\n\n // DPoP header per RFC 9449 Section 4.2\n // MUST include typ, alg, and jwk (public key)\n const header = {\n typ: \"dpop+jwt\",\n alg: \"ES256\",\n jwk: publicKeyJwk, // Public key in JWK format\n };\n\n // Parse URL to get htu without query/fragment\n // Use window.location.origin as base for relative URLs\n const url = new URL(\n httpUri,\n typeof window !== \"undefined\" ? window.location.origin : undefined\n );\n const htu = `${url.origin}${url.pathname}`;\n\n // DPoP payload per RFC 9449 Section 4.2\n const payload: Record<string, string | number> = {\n jti: crypto.randomUUID(),\n htm: httpMethod.toUpperCase(),\n htu: htu,\n iat: Math.floor(Date.now() / 1000),\n };\n\n if (accessToken) {\n const tokenBytes = new TextEncoder().encode(accessToken);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", tokenBytes);\n payload.ath = arrayBufferToBase64url(hashBuffer);\n }\n\n const encodedHeader = arrayBufferToBase64url(\n new TextEncoder().encode(JSON.stringify(header)).buffer as ArrayBuffer\n );\n const encodedPayload = arrayBufferToBase64url(\n new TextEncoder().encode(JSON.stringify(payload)).buffer as ArrayBuffer\n );\n\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n const signatureBuffer = await crypto.subtle.sign(\n {\n name: \"ECDSA\",\n hash: { name: \"SHA-256\" },\n },\n privateKey,\n new TextEncoder().encode(signatureInput)\n );\n const signature = arrayBufferToBase64url(signatureBuffer);\n\n return `${encodedHeader}.${encodedPayload}.${signature}`;\n } catch (err) {\n console.error(\"Failed to generate DPoP proof:\", err);\n return null;\n }\n}\n\n/**\n * Check if DPoP is enabled (Keys are stored)\n */\nexport async function isDPoPEnabled(): Promise<boolean> {\n const key = await getDPoPKey();\n return key !== null;\n}\n\n // Legacy export for backward compatibility\nexport const storeDPoPKey = storeDPoPPrivateKey;\n\nconst WebAuthn = {\n isWebAuthnSupported,\n isConditionalUISupported,\n arrayBufferToBase64,\n base64ToArrayBuffer,\n arrayBufferToBase64url,\n base64urlToArrayBuffer,\n stringToArrayBuffer,\n uint8ArrayToString,\n getPasskeyEmail,\n setPasskeyEmail,\n clearPasskeyEmail,\n toMinimalJWK,\n calculateThumbprint,\n getDPoPKey,\n getDPoPPublicKeyJWK,\n clearDPoPKey,\n generateDPoPKeyPair,\n generateDPoPProof,\n isDPoPEnabled,\n storeDPoPKey,\n};\n\n// if (typeof window !== \"undefined\") {\n// (window as unknown as { WebAuthn: typeof WebAuthn }).WebAuthn = WebAuthn;\n// }\n\n// var global: any = window || global;\n// global.WebAuthn = WebAuthn;\n// global.webauthnReady = () => {\n// document.dispatchEvent(new CustomEvent(\"webauthnReady\"));\n// };","import {\n arrayBufferToBase64,\n generateDPoPKeyPair,\n generateDPoPProof,\n stringToArrayBuffer,\n clearDPoPKey,\n base64ToArrayBuffer,\n} from \"./webauthn\";\n\ninterface AuthSDKConfig {\n apiKey?: string;\n}\n\nconst LOCALSTORAGE_TOKEN_KEY = \"postex-auth-token\";\n\ntype AuthStatusType = \"no_session\" | \"session_found\" | \"webauthn_ready\";\n\ninterface AuthStatusResponse {\n status: AuthStatusType;\n email?: string;\n webauthn?: boolean;\n challenge?: string;\n credentialIds?: string[];\n rp?: { name: string; host: string };\n}\n\n/** Response from POST /auth/initiate */\ntype InitiateAuthStatusType = \"webauthn_challenge\" | \"otp_sent\";\n\ninterface InitiateAuthResponse {\n status: InitiateAuthStatusType;\n challenge?: string;\n credentialIds?: string[];\n rp?: { name: string; host: string };\n}\n\ninterface OTPVerifyResponse {\n access_token: string;\n id_token: string;\n refresh_token: string;\n expires_in: number;\n token_type: string;\n verified: boolean;\n email: string;\n [key: string]: any;\n}\n\ninterface PasskeyRegistrationChallenge {\n challenge: string;\n rp: { name: string; id: string };\n user: { id: string; name: string; displayName: string };\n pubKeyCredParams?: Array<{ type: string; alg: number }>;\n authenticatorSelection?: AuthenticatorSelectionCriteria;\n timeout?: number;\n attestation?: AttestationConveyancePreference;\n /** Existing credential IDs to exclude (prevents duplicate registration) */\n excludeCredentials?: Array<{\n id: string;\n type: \"public-key\";\n transports?: AuthenticatorTransport[];\n }>;\n}\n\ninterface PasskeyRegisterResponse {\n registered: boolean;\n [key: string]: any;\n}\n\ninterface PasskeyStatusResponse {\n credentialId?: string;\n hasCredentials: boolean;\n [key: string]: any;\n}\n\ninterface AuthResponse {\n access_token: string;\n refresh_token: string;\n id_token?: string;\n email: string;\n name: string;\n expiresIn?: number;\n tokenType?: string;\n [key: string]: any;\n}\n\n/** Response from POST /auth/refresh */\ninterface RefreshTokenResponse {\n access_token: string;\n id_token?: string;\n token_type: string;\n expires_in: number;\n}\n\nconst DEFAULT_BASE_URL = \"http://localhost:3200\";\n\nexport class AuthSDKFetchError extends Error {\n response: { status: number; data?: any };\n\n constructor(status: number, data?: any, message?: string) {\n super(message ?? `Request failed with status ${status}`);\n this.response = { status, data };\n this.name = \"AuthSDKFetchError\";\n }\n}\n\nconst ID_TOKEN_KEY = \"auth_sdk_id_token\";\nconst REFRESH_TOKEN_KEY = \"auth_sdk_refresh_token\";\n\nexport class AuthSDK {\n private config: AuthSDKConfig;\n\n constructor(config: AuthSDKConfig) {\n this.config = config;\n }\n\n private buildUrl(path: string, params?: Record<string, string>): string {\n const base = DEFAULT_BASE_URL.replace(/\\/$/, \"\");\n const pathNorm = path.startsWith(\"/\") ? path : `/${path}`;\n const url = `${base}${pathNorm}`;\n if (!params || Object.keys(params).length === 0) return url;\n const search = new URLSearchParams(params).toString();\n return `${url}?${search}`;\n }\n\n private async request<T>(\n method: string,\n path: string,\n options?: {\n body?: any;\n params?: Record<string, string>;\n headers?: Record<string, string>;\n }\n ): Promise<{ data: T }> {\n const url = this.buildUrl(path, options?.params);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"X-API-Key\": this.config.apiKey ?? \"\",\n ...options?.headers,\n };\n\n const init: RequestInit = {\n method,\n credentials: \"include\",\n headers,\n };\n if (options?.body !== undefined && options?.body !== null) {\n init.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, init);\n\n if (!response.ok) {\n let data: any;\n try {\n const text = await response.text();\n data = text ? JSON.parse(text) : undefined;\n } catch {\n data = undefined;\n }\n if (response.status === 401) {\n await this.clearTokens();\n }\n throw new AuthSDKFetchError(response.status, data);\n }\n\n const text = await response.text();\n const data = text ? JSON.parse(text) : {};\n return { data };\n }\n\n /**\n * Returns auth headers (Authorization + DPoP) for the given request.\n * Use this to attach auth to your own HTTP client (e.g. axios request interceptor).\n * @param method - HTTP method (e.g. \"GET\", \"POST\")\n * @param url - Full request URL\n */\n async getRequestAuthHeaders(\n method: string,\n url: string\n ): Promise<Record<string, string>> {\n const token = localStorage.getItem(LOCALSTORAGE_TOKEN_KEY);\n if (!token) return {};\n const fullUrl = url.startsWith(\"http\") ? url : `${DEFAULT_BASE_URL}${url}`;\n const dpopProof = await generateDPoPProof(\n method.toUpperCase(),\n fullUrl,\n token\n );\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n if (dpopProof) headers[\"DPoP\"] = dpopProof;\n return headers;\n }\n\n /**\n * GET /auth/status - Check if client has trusted device session and what auth method is available.\n * Returns no_session | session_found | webauthn_ready per PostEx Auth BFF spec.\n */\n async getStatus(email: string): Promise<AuthStatusResponse> {\n const response = await this.request<unknown>(\"GET\", \"/auth/status\", {\n params: { email },\n });\n return (response.data as any).data ?? response.data;\n }\n\n /**\n * POST /auth/initiate - Unified entry: returns webauthn_challenge or otp_sent.\n * Sets auth_session cookie when otp_sent.\n */\n async initiateAuth(email: string): Promise<InitiateAuthResponse> {\n const response = await this.request<unknown>(\"POST\", \"/auth/initiate\", {\n body: { email },\n });\n const data = (response.data as any).data ?? response.data;\n return {\n status: data.status,\n challenge: data.challenge,\n credentialIds: data.credentialIds,\n rp: data.rp,\n };\n }\n\n /**\n * POST /otp/verify - Verifies the OTP code entered by the user.\n * Stores tokens from the response.\n */\n async verifyOTP(otp: string): Promise<OTPVerifyResponse> {\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/otp/verify`\n );\n\n const response = await this.request<unknown>(\"POST\", \"/otp/verify\", {\n body: { otp },\n headers: dpopProof ? { DPoP: dpopProof } : {},\n });\n const data = (response.data as any).data ?? response.data;\n\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.access_token ?? result.accessToken ?? result.AccessToken;\n const refreshToken =\n result.refresh_token ?? result.refreshToken ?? result.RefreshToken;\n const idToken = result.id_token ?? result.idToken ?? result.IdToken;\n const expiresIn =\n result.expires_in ?? result.expiresIn ?? result.ExpiresIn ?? 3600;\n const tokenType =\n result.token_type ?? result.tokenType ?? result.TokenType ?? \"Bearer\";\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: expiresIn ?? 3600,\n tokenType: tokenType ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken ?? \"\",\n expires_in: expiresIn,\n token_type: tokenType,\n verified: result.verified ?? result.Verified ?? true,\n email: result.email ?? result.Email ?? \"\",\n ...result,\n };\n }\n\n /**\n * GET /magic-link - Verify a magic link token.\n * Sets auth_session cookie on success.\n */\n async verifyMagicLink(token: string, email: string): Promise<void> {\n await this.request(\"GET\", \"/verify/magic-link\", {\n params: { token, email, redirect_mode: \"frontend\" },\n });\n }\n\n /**\n * POST /magic-link/complete - Complete magic link authentication.\n * Requires auth_session cookie set by verifyMagicLink.\n * Stores tokens from the response.\n */\n async completeMagicLink(): Promise<OTPVerifyResponse> {\n const response = await this.request<unknown>(\n \"POST\",\n \"/verify/magic-link/complete\",\n {\n body: {},\n }\n );\n const data = (response.data as any).data ?? response.data;\n\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.access_token ?? result.accessToken ?? result.AccessToken;\n const refreshToken =\n result.refresh_token ?? result.refreshToken ?? result.RefreshToken;\n const idToken = result.id_token ?? result.idToken ?? result.IdToken;\n const expiresIn =\n result.expires_in ?? result.expiresIn ?? result.ExpiresIn ?? 3600;\n const tokenType =\n result.token_type ?? result.tokenType ?? result.TokenType ?? \"Bearer\";\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: expiresIn ?? 3600,\n tokenType: tokenType ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken ?? \"\",\n expires_in: expiresIn,\n token_type: tokenType,\n verified: result.verified ?? result.Verified ?? true,\n email: result.email ?? result.Email ?? \"\",\n ...result,\n };\n }\n\n async initiatePasskeyRegistration(): Promise<PasskeyRegistrationChallenge> {\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/initiate/challenge\",\n {\n body: {},\n }\n );\n return (response.data as any).data ?? response.data;\n }\n\n async registerPasskey(email: string): Promise<PasskeyRegisterResponse> {\n const challenge = await this.initiatePasskeyRegistration();\n let userIdBuffer: ArrayBuffer;\n if (challenge?.user?.id) {\n try {\n userIdBuffer = base64ToArrayBuffer(challenge.user.id);\n } catch {\n userIdBuffer = stringToArrayBuffer(challenge.user.id);\n }\n } else {\n userIdBuffer = stringToArrayBuffer(email);\n }\n\n const pubKeyCredParams = (\n challenge.pubKeyCredParams ?? [\n { type: \"public-key\", alg: -7 },\n { type: \"public-key\", alg: -257 },\n ]\n ).map((param) => ({\n type: \"public-key\" as const,\n alg: param.alg,\n }));\n\n const excludeCredentials: PublicKeyCredentialDescriptor[] | undefined =\n challenge.excludeCredentials?.map((cred) => ({\n type: \"public-key\" as const,\n id: base64ToArrayBuffer(cred.id),\n transports: cred.transports,\n }));\n\n const createOptions: PublicKeyCredentialCreationOptions = {\n challenge: base64ToArrayBuffer(challenge.challenge),\n rp: {\n name: challenge.rp?.name ?? \"XPay\",\n id: challenge.rp?.id ?? window.location.hostname,\n },\n user: {\n id: userIdBuffer,\n name: challenge.user?.name ?? email,\n displayName: challenge.user?.displayName ?? email,\n },\n pubKeyCredParams,\n timeout: challenge.timeout ?? 60000,\n attestation: challenge.attestation ?? \"none\",\n authenticatorSelection: challenge.authenticatorSelection ?? {\n residentKey: \"required\",\n userVerification: \"required\",\n },\n };\n\n const credential = (await navigator.credentials.create({\n publicKey: createOptions,\n })) as PublicKeyCredential;\n\n if (!credential) throw new Error(\"Credential creation failed\");\n const attResp = credential.response as AuthenticatorAttestationResponse;\n const payload = {\n clientDataJSON: arrayBufferToBase64(attResp.clientDataJSON),\n attestationObject: arrayBufferToBase64(attResp.attestationObject),\n rawId: arrayBufferToBase64(credential.rawId as ArrayBuffer),\n }; \n if (!payload.rawId) throw new Error(\"Raw ID is required\");\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/webauthn/register/challenge`\n );\n\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/register/challenge\",\n {\n body: payload,\n headers: dpopProof ? { DPoP: dpopProof } : {},\n }\n );\n\n return (response.data as any).data ?? response.data;\n }\n\n /**\n * POST /webauthn/authenticate/challenge - Authenticate with passkey.\n */\n async authenticateWithPasskey({\n challenge,\n rp,\n credentialIds,\n }: {\n challenge: string;\n rp: { name: string; host: string };\n credentialIds: string[];\n }): Promise<AuthResponse> {\n const assertion = (await navigator.credentials.get({\n publicKey: {\n challenge: base64ToArrayBuffer(challenge),\n rpId: rp?.host ?? undefined,\n allowCredentials: credentialIds.map((id: string) => ({\n type: \"public-key\" as const,\n id: base64ToArrayBuffer(id),\n // Hint browser about possible transports for faster authenticator discovery\n // transports: [\"internal\", \"hybrid\"] as AuthenticatorTransport[],\n })),\n timeout: 60000,\n userVerification: \"required\",\n },\n })) as PublicKeyCredential;\n\n if (!assertion) throw new Error(\"Authentication failed\");\n const assertionResponse =\n assertion.response as AuthenticatorAssertionResponse;\n const payload = {\n clientDataJSON: arrayBufferToBase64(assertionResponse.clientDataJSON),\n authenticatorData: arrayBufferToBase64(\n assertionResponse.authenticatorData\n ),\n signature: arrayBufferToBase64(assertionResponse.signature),\n rawId: arrayBufferToBase64(assertion.rawId as ArrayBuffer),\n userHandle: assertionResponse.userHandle\n ? arrayBufferToBase64(assertionResponse.userHandle)\n : \"\",\n };\n\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/webauthn/authenticate/challenge`\n );\n\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/authenticate/challenge\",\n {\n body: payload,\n headers: dpopProof ? { DPoP: dpopProof } : {},\n }\n );\n\n const data = (response.data as any).data ?? response.data;\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.AccessToken ?? result.accessToken ?? result.access_token;\n const refreshToken =\n result.RefreshToken ?? result.refreshToken ?? result.refresh_token;\n const idToken = result.IdToken ?? result.idToken ?? result.id_token;\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: result.expiresIn ?? result.ExpiresIn ?? 3600,\n tokenType: result.tokenType ?? result.token_type ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken,\n email: result.email,\n name: result.name ?? result.userName,\n expiresIn: result.expiresIn ?? result.ExpiresIn,\n tokenType: result.tokenType ?? result.token_type,\n ...result,\n };\n }\n /**\n * GET /webauthn/credentials/:username - Get user's passkey status.\n */\n async getPasskeyStatus(username: string): Promise<PasskeyStatusResponse> {\n const encoded = encodeURIComponent(username);\n const path = `/webauthn/credentials/${encoded}`;\n const signed = await this.signRequest(\"GET\", path);\n const response = await this.request<unknown>(\"GET\", path, {\n headers: signed.headers as Record<string, string>,\n });\n const data = (response.data as any).data ?? response.data;\n return {\n ...data,\n hasCredentials: Boolean(data.hasCredentials ?? data.credentialId),\n };\n }\n\n /**\n * DELETE /webauthn/credentials/:username - Remove passkey.\n */\n async removePasskey(username: string): Promise<void> {\n const encoded = encodeURIComponent(username);\n const path = `/webauthn/credentials/${encoded}`;\n const signed = await this.signRequest(\"DELETE\", path);\n await this.request(\"DELETE\", path, {\n headers: signed.headers as Record<string, string>,\n });\n }\n\n /**\n * Signs a request with DPoP and Authorization headers (internal use).\n */\n async signRequest(\n method: string,\n url: string,\n config: any = {}\n ): Promise<any> {\n const fullUrl = url.startsWith(\"http\") ? url : `${DEFAULT_BASE_URL}${url}`;\n const authHeaders = await this.getRequestAuthHeaders(method, fullUrl);\n return { ...config, headers: { ...config.headers, ...authHeaders } };\n }\n\n /**\n * Replaces native fetch or Axios with a DPoP-signed version.\n */\n async authenticatedFetch(\n input: RequestInfo | URL,\n init?: RequestInit\n ): Promise<Response> {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n const method = init?.method || \"GET\";\n\n const signedInit = await this.signRequest(method, url, {\n headers: init?.headers,\n });\n return fetch(input, { ...init, headers: signedInit.headers });\n }\n\n /**\n * Store tokens from /webauthn/authenticate (per spec: sessionStorage preferred).\n */\n async storeTokens(tokens: {\n accessToken: string;\n refreshToken?: string;\n idToken?: string;\n expiresIn?: number;\n tokenType?: string;\n }): Promise<void> {\n localStorage.setItem(LOCALSTORAGE_TOKEN_KEY, tokens.accessToken);\n if (tokens.refreshToken) {\n localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken);\n }\n if (tokens.idToken) {\n localStorage.setItem(ID_TOKEN_KEY, tokens.idToken);\n }\n }\n\n /**\n * Clear stored tokens (call on logout).\n */\n async clearTokens(): Promise<void> {\n localStorage.removeItem(LOCALSTORAGE_TOKEN_KEY);\n localStorage.removeItem(ID_TOKEN_KEY);\n localStorage.removeItem(REFRESH_TOKEN_KEY);\n }\n\n /**\n * POST /auth/refresh - Refresh access token using server-stored refresh token.\n * Requires trusted device cookie (td). Refresh token is stored server-side.\n * Rate limit: 10 requests per minute.\n */\n async refreshToken(): Promise<RefreshTokenResponse> {\n const response = await this.request<unknown>(\"POST\", \"/auth/refresh\", {\n body: {},\n });\n const data = (response.data as any).data ?? response.data;\n\n const accessToken = data.access_token;\n const idToken = data.id_token ?? \"\";\n const tokenType = data.token_type ?? \"Bearer\";\n const expiresIn = data.expires_in ?? 3600;\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n idToken,\n expiresIn,\n tokenType,\n });\n }\n\n return {\n access_token: accessToken,\n id_token: idToken,\n token_type: tokenType,\n expires_in: expiresIn,\n };\n }\n\n /**\n * POST /auth/logout - Logout from the current device.\n * Revokes the current token and trusted device, then clears local tokens.\n */\n async logout(): Promise<void> {\n try {\n const token = await this.getAccessToken();\n const headers: Record<string, string> = {};\n if (token) {\n headers[\"Authorization\"] = `Bearer ${token}`;\n }\n await this.request(\"POST\", \"/auth/logout\", { body: {}, headers });\n clearDPoPKey();\n } catch {\n // Silently fail - proceed with local cleanup\n }\n await this.clearTokens();\n }\n\n async getAccessToken(): Promise<string | null> {\n return localStorage.getItem(LOCALSTORAGE_TOKEN_KEY);\n }\n}\n\n// Expose SDK on global window for use by other JS projects (e.g. script tag / iframe)\n// if (typeof window !== \"undefined\") {\n// (window as unknown as { AuthSDK: typeof AuthSDK }).AuthSDK = AuthSDK;\n// }\n\n// var global: any = window || global;\n// global.AuthSDK = AuthSDK;\n// global.authsdkReady = () => {\n// document.dispatchEvent(new CustomEvent(\"authsdkReady\"));\n// };\n"],"names":["isWebAuthnSupported","isConditionalUISupported","arrayBufferToBase64","buffer","bytes","binary","i","base64ToArrayBuffer","base64","cleaned","pad","padded","arrayBufferToBase64url","isUUID","str","uuidToArrayBuffer","uuid","hex","base64urlToArrayBuffer","input","stringToArrayBuffer","uint8ArrayToString","arr","DB_NAME","DB_VERSION","STORE_NAME","PASSKEY_EMAIL_KEY","openDB","resolve","reject","request","db","getPasskeyEmail","tx","setPasskeyEmail","email","clearPasskeyEmail","DPOP_PRIVATE_KEY_STORAGE_KEY","DPOP_PUBLIC_KEY_JWK_STORAGE_KEY","toMinimalJWK","jwk","calculateThumbprint","canonical","hash","storeDPoPPrivateKey","key","err","storeDPoPPublicKeyJWK","getDPoPKey","getDPoPPublicKeyJWK","clearDPoPKey","store","generateDPoPKeyPair","keyPair","fullJwk","minimalJwk","thumbprint","generateDPoPProof","httpMethod","httpUri","accessToken","privateKey","publicKeyJwk","header","url","htu","payload","tokenBytes","hashBuffer","encodedHeader","encodedPayload","signatureInput","signatureBuffer","signature","isDPoPEnabled","storeDPoPKey","LOCALSTORAGE_TOKEN_KEY","DEFAULT_BASE_URL","AuthSDKFetchError","status","data","message","ID_TOKEN_KEY","REFRESH_TOKEN_KEY","AuthSDK","config","path","params","base","pathNorm","search","method","options","headers","init","response","text","token","fullUrl","dpopProof","otp","result","refreshToken","idToken","expiresIn","tokenType","challenge","userIdBuffer","pubKeyCredParams","param","cred","createOptions","credential","attResp","rp","credentialIds","assertion","id","assertionResponse","username","signed","authHeaders","signedInit","tokens"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(c,w){typeof exports=="object"&&typeof module<"u"?w(exports):typeof define=="function"&&define.amd?define(["exports"],w):(c=typeof globalThis<"u"?globalThis:c||self,w(c.PostexAuthSDK={}))})(this,(function(c){"use strict";function w(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function N(){if(!w())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function f(o){const n=new Uint8Array(o);let t="";for(let e=0;e<n.byteLength;e++)t+=String.fromCharCode(n[e]);return btoa(t)}function k(o){if(typeof o!="string"||!o)throw new Error("Invalid base64: expected non-empty string");const n=o.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),t=n.length%4,e=t>0?n+"=".repeat(4-t):n;try{const a=atob(e),r=new Uint8Array(a.length);for(let s=0;s<a.length;s++)r[s]=a.charCodeAt(s);return r.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function g(o){return f(o).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function J(o){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(o)}function j(o){const n=o.replace(/-/g,""),t=new Uint8Array(n.length/2);for(let e=0;e<t.length;e++)t[e]=parseInt(n.substr(e*2,2),16);return t.buffer}function L(o){if(!o||typeof o!="string")throw new Error("Invalid input: expected non-empty string");return J(o)?j(o):k(o)}function E(o){return new TextEncoder().encode(o).buffer}function W(o){return String.fromCharCode(...o)}const H="xpay_webauthn",M=1,u="passkey_data",I="passkey_email";function p(){return new Promise((o,n)=>{const t=indexedDB.open(H,M);t.onerror=()=>n(t.error),t.onsuccess=()=>o(t.result),t.onupgradeneeded=()=>{const e=t.result;e.objectStoreNames.contains(u)||e.createObjectStore(u)}})}async function F(){try{const o=await p();return new Promise((n,t)=>{const e=o.transaction(u,"readonly"),r=e.objectStore(u).get(I);r.onerror=()=>t(r.error),r.onsuccess=()=>n(r.result??null),e.oncomplete=()=>o.close()})}catch{return null}}async function Y(o){try{const n=await p();return new Promise((t,e)=>{const a=n.transaction(u,"readwrite"),s=a.objectStore(u).put(o,I);s.onerror=()=>e(s.error),s.onsuccess=()=>t(),a.oncomplete=()=>n.close()})}catch{}}async function G(){try{const o=await p();return new Promise((n,t)=>{const e=o.transaction(u,"readwrite"),r=e.objectStore(u).delete(I);r.onerror=()=>t(r.error),r.onsuccess=()=>n(),e.oncomplete=()=>o.close()})}catch{}}const A="dpop_private_key",K="dpop_public_key_jwk";function O(o){return{kty:"EC",crv:"P-256",x:o.x,y:o.y}}async function x(o){const n=JSON.stringify({crv:o.crv,kty:o.kty,x:o.x,y:o.y}),t=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(n));return g(t)}async function B(o){try{const n=await p();return new Promise((t,e)=>{const a=n.transaction(u,"readwrite"),s=a.objectStore(u).put(o,A);s.onerror=()=>e(s.error),s.onsuccess=()=>t(),a.oncomplete=()=>n.close()})}catch(n){console.error("Failed to store DPoP private key:",n)}}async function V(o){try{const n=await p();return new Promise((t,e)=>{const a=n.transaction(u,"readwrite"),s=a.objectStore(u).put(o,K);s.onerror=()=>e(s.error),s.onsuccess=()=>t(),a.oncomplete=()=>n.close()})}catch(n){console.error("Failed to store DPoP public key JWK:",n)}}async function D(){try{const o=await p();return new Promise((n,t)=>{const e=o.transaction(u,"readonly"),r=e.objectStore(u).get(A);r.onerror=()=>t(r.error),r.onsuccess=()=>n(r.result??null),e.oncomplete=()=>o.close()})}catch{return null}}async function q(){try{const o=await p();return new Promise((n,t)=>{const e=o.transaction(u,"readonly"),r=e.objectStore(u).get(K);r.onerror=()=>t(r.error),r.onsuccess=()=>n(r.result??null),e.oncomplete=()=>o.close()})}catch{return null}}async function R(){try{const o=await p();return new Promise((n,t)=>{const e=o.transaction(u,"readwrite"),a=e.objectStore(u);a.delete(A),a.delete(K),e.onerror=()=>t(e.error),e.oncomplete=()=>{o.close(),n()}})}catch{}}async function b(){const o=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),n=await crypto.subtle.exportKey("jwk",o.publicKey),t=O(n),e=await x(t);return await B(o.privateKey),await V(t),{publicKey:t,thumbprint:e}}async function P(o,n,t){try{const e=await D(),a=await q();if(!e||!a)return null;const r={typ:"dpop+jwt",alg:"ES256",jwk:a},s=new URL(n,typeof window<"u"?window.location.origin:void 0),d=`${s.origin}${s.pathname}`,l={jti:crypto.randomUUID(),htm:o.toUpperCase(),htu:d,iat:Math.floor(Date.now()/1e3)};if(t){const v=new TextEncoder().encode(t),Z=await crypto.subtle.digest("SHA-256",v);l.ath=g(Z)}const h=g(new TextEncoder().encode(JSON.stringify(r)).buffer),i=g(new TextEncoder().encode(JSON.stringify(l)).buffer),y=`${h}.${i}`,S=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},e,new TextEncoder().encode(y)),_=g(S);return`${h}.${i}.${_}`}catch(e){return console.error("Failed to generate DPoP proof:",e),null}}async function z(){return await D()!==null}const X=B,m="postex-auth-token",T="http://localhost:3200";class C extends Error{constructor(n,t,e){super(e??`Request failed with status ${n}`),this.response={status:n,data:t},this.name="AuthSDKFetchError"}}const $="auth_sdk_id_token",U="auth_sdk_refresh_token";class Q{constructor(n){this.config=n}buildUrl(n,t){const e=T.replace(/\/$/,""),a=n.startsWith("/")?n:`/${n}`,r=`${e}${a}`;if(!t||Object.keys(t).length===0)return r;const s=new URLSearchParams(t).toString();return`${r}?${s}`}async request(n,t,e){const a=this.buildUrl(t,e?.params),r={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...e?.headers},s={method:n,credentials:"include",headers:r};e?.body!==void 0&&e?.body!==null&&(s.body=JSON.stringify(e.body));const d=await fetch(a,s);if(!d.ok){let i;try{const y=await d.text();i=y?JSON.parse(y):void 0}catch{i=void 0}throw d.status===401&&await this.clearTokens(),new C(d.status,i)}const l=await d.text();return{data:l?JSON.parse(l):{}}}async getRequestAuthHeaders(n,t){const e=localStorage.getItem(m);if(!e)return{};const a=t.startsWith("http")?t:`${T}${t}`,r=await P(n.toUpperCase(),a,e),s={Authorization:`Bearer ${e}`};return r&&(s.DPoP=r),s}async getStatus(n){const t=await this.request("GET","/auth/status",{params:{email:n}});return t.data.data??t.data}async initiateAuth(n){const t=await this.request("POST","/auth/initiate",{body:{email:n}}),e=t.data.data??t.data;return{status:e.status,challenge:e.challenge,credentialIds:e.credentialIds,rp:e.rp}}async verifyOTP(n){await b();const t=await P("POST",`${T}/otp/verify`),e=await this.request("POST","/otp/verify",{body:{otp:n},headers:t?{DPoP:t}:{}}),a=e.data.data??e.data,r=a.AuthenticationResult??a,s=r.access_token??r.accessToken??r.AccessToken,d=r.refresh_token??r.refreshToken??r.RefreshToken,l=r.id_token??r.idToken??r.IdToken,h=r.expires_in??r.expiresIn??r.ExpiresIn??3600,i=r.token_type??r.tokenType??r.TokenType??"Bearer";return s&&await this.storeTokens({accessToken:s,refreshToken:d??"",idToken:l??"",expiresIn:h??3600,tokenType:i??"Bearer"}),{access_token:s,refresh_token:d??"",id_token:l??"",expires_in:h,token_type:i,verified:r.verified??r.Verified??!0,email:r.email??r.Email??"",...r}}async verifyMagicLink(n,t){await this.request("GET","/verify/magic-link",{params:{token:n,email:t,redirect_mode:"frontend"}})}async completeMagicLink(){const n=await this.request("POST","/verify/magic-link/complete",{body:{}}),t=n.data.data??n.data,e=t.AuthenticationResult??t,a=e.access_token??e.accessToken??e.AccessToken,r=e.refresh_token??e.refreshToken??e.RefreshToken,s=e.id_token??e.idToken??e.IdToken,d=e.expires_in??e.expiresIn??e.ExpiresIn??3600,l=e.token_type??e.tokenType??e.TokenType??"Bearer";return a&&await this.storeTokens({accessToken:a,refreshToken:r??"",idToken:s??"",expiresIn:d??3600,tokenType:l??"Bearer"}),{access_token:a,refresh_token:r??"",id_token:s??"",expires_in:d,token_type:l,verified:e.verified??e.Verified??!0,email:e.email??e.Email??"",...e}}async initiatePasskeyRegistration(){const n=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return n.data.data??n.data}async registerPasskey(n){const t=await this.initiatePasskeyRegistration();let e;if(t?.user?.id)try{e=k(t.user.id)}catch{e=E(t.user.id)}else e=E(n);const a=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(y=>({type:"public-key",alg:y.alg}));t.excludeCredentials?.map(y=>({type:"public-key",id:k(y.id),transports:y.transports}));const r={challenge:k(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:e,name:t.user?.name??n,displayName:t.user?.displayName??n},pubKeyCredParams:a,timeout:t.timeout??6e4,attestation:t.attestation??"none",authenticatorSelection:t.authenticatorSelection??{residentKey:"required",userVerification:"required"}},s=await navigator.credentials.create({publicKey:r});if(!s)throw new Error("Credential creation failed");const d=s.response,l={clientDataJSON:f(d.clientDataJSON),attestationObject:f(d.attestationObject),rawId:f(s.rawId)};if(!l.rawId)throw new Error("Raw ID is required");await b();const h=await P("POST",`${T}/webauthn/register/challenge`),i=await this.request("POST","/webauthn/register/challenge",{body:l,headers:h?{DPoP:h}:{}});return i.data.data??i.data}async authenticateWithPasskey({challenge:n,rp:t,credentialIds:e}){const a=await navigator.credentials.get({publicKey:{challenge:k(n),rpId:t?.host??void 0,allowCredentials:e.map(v=>({type:"public-key",id:k(v)})),timeout:6e4,userVerification:"required"}});if(!a)throw new Error("Authentication failed");const r=a.response,s={clientDataJSON:f(r.clientDataJSON),authenticatorData:f(r.authenticatorData),signature:f(r.signature),rawId:f(a.rawId),userHandle:r.userHandle?f(r.userHandle):""};await b();const d=await P("POST",`${T}/webauthn/authenticate/challenge`),l=await this.request("POST","/webauthn/authenticate/challenge",{body:s,headers:d?{DPoP:d}:{}}),h=l.data.data??l.data,i=h.AuthenticationResult??h,y=i.AccessToken??i.accessToken??i.access_token,S=i.RefreshToken??i.refreshToken??i.refresh_token,_=i.IdToken??i.idToken??i.id_token;return y&&await this.storeTokens({accessToken:y,refreshToken:S??"",idToken:_??"",expiresIn:i.expiresIn??i.ExpiresIn??3600,tokenType:i.tokenType??i.token_type??"Bearer"}),{access_token:y,refresh_token:S??"",id_token:_,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(n){const e=`/webauthn/credentials/${encodeURIComponent(n)}`,a=await this.signRequest("GET",e),r=await this.request("GET",e,{headers:a.headers}),s=r.data.data??r.data;return{...s,hasCredentials:!!(s.hasCredentials??s.credentialId)}}async removePasskey(n){const e=`/webauthn/credentials/${encodeURIComponent(n)}`,a=await this.signRequest("DELETE",e);await this.request("DELETE",e,{headers:a.headers})}async signRequest(n,t,e={}){const a=t.startsWith("http")?t:`${T}${t}`,r=await this.getRequestAuthHeaders(n,a);return{...e,headers:{...e.headers,...r}}}async authenticatedFetch(n,t){const e=typeof n=="string"?n:n instanceof URL?n.toString():n.url,a=t?.method||"GET",r=await this.signRequest(a,e,{headers:t?.headers});return fetch(n,{...t,headers:r.headers})}async storeTokens(n){localStorage.setItem(m,n.accessToken),n.refreshToken&&localStorage.setItem(U,n.refreshToken),n.idToken&&localStorage.setItem($,n.idToken)}async clearTokens(){localStorage.removeItem(m),localStorage.removeItem($),localStorage.removeItem(U)}async refreshToken(){const n=await this.request("POST","/auth/refresh",{body:{}}),t=n.data.data??n.data,e=t.access_token,a=t.id_token??"",r=t.token_type??"Bearer",s=t.expires_in??3600;return e&&await this.storeTokens({accessToken:e,idToken:a,expiresIn:s,tokenType:r}),{access_token:e,id_token:a,token_type:r,expires_in:s}}async logout(){try{const n=await this.getAccessToken(),t={};n&&(t.Authorization=`Bearer ${n}`),await this.request("POST","/auth/logout",{body:{},headers:t}),R()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(m)}}c.AuthSDK=Q,c.AuthSDKFetchError=C,c.arrayBufferToBase64=f,c.arrayBufferToBase64url=g,c.base64ToArrayBuffer=k,c.base64urlToArrayBuffer=L,c.calculateThumbprint=x,c.clearDPoPKey=R,c.clearPasskeyEmail=G,c.generateDPoPKeyPair=b,c.generateDPoPProof=P,c.getDPoPKey=D,c.getDPoPPublicKeyJWK=q,c.getPasskeyEmail=F,c.isConditionalUISupported=N,c.isDPoPEnabled=z,c.isWebAuthnSupported=w,c.setPasskeyEmail=Y,c.storeDPoPKey=X,c.stringToArrayBuffer=E,c.toMinimalJWK=O,c.uint8ArrayToString=W,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
|
|
2
|
+
//# sourceMappingURL=postex-auth-sdk.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postex-auth-sdk.umd.js","sources":["../src/webauthn.ts","../src/auth.ts"],"sourcesContent":["export function isWebAuthnSupported(): boolean {\n return (\n typeof window !== \"undefined\" &&\n typeof window.PublicKeyCredential !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n typeof navigator.credentials !== \"undefined\"\n );\n}\n\nexport async function isConditionalUISupported(): Promise<boolean> {\n if (!isWebAuthnSupported()) return false;\n try {\n return (\n (await PublicKeyCredential.isConditionalMediationAvailable?.()) ?? false\n );\n } catch {\n return false;\n }\n}\n\nexport function arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n if (typeof base64 !== \"string\" || !base64) {\n throw new Error(\"Invalid base64: expected non-empty string\");\n }\n const cleaned = base64\n .replace(/\\s/g, \"\")\n .replace(/-/g, \"+\")\n .replace(/_/g, \"/\");\n const pad = cleaned.length % 4;\n const padded = pad > 0 ? cleaned + \"=\".repeat(4 - pad) : cleaned;\n try {\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer as ArrayBuffer;\n } catch (e) {\n throw new Error(\n \"Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.\"\n );\n }\n}\n\nexport function arrayBufferToBase64url(buffer: ArrayBuffer): string {\n const base64 = arrayBufferToBase64(buffer);\n return base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n}\n\nfunction isUUID(str: string): boolean {\n return /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(\n str\n );\n}\n\nfunction uuidToArrayBuffer(uuid: string): ArrayBuffer {\n const hex = uuid.replace(/-/g, \"\");\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\n }\n return bytes.buffer as ArrayBuffer;\n}\n\nexport function base64urlToArrayBuffer(input: string): ArrayBuffer {\n if (!input || typeof input !== \"string\") {\n throw new Error(\"Invalid input: expected non-empty string\");\n }\n // If it looks like a UUID, convert hex to bytes\n if (isUUID(input)) {\n return uuidToArrayBuffer(input);\n }\n // Otherwise treat as base64/base64url\n return base64ToArrayBuffer(input);\n}\n\nexport function stringToArrayBuffer(str: string): ArrayBuffer {\n return new TextEncoder().encode(str).buffer as ArrayBuffer;\n}\n\nexport function uint8ArrayToString(arr: Uint8Array): string {\n return String.fromCharCode(...arr);\n}\n\nconst DB_NAME = \"xpay_webauthn\";\nconst DB_VERSION = 1;\nconst STORE_NAME = \"passkey_data\";\nconst PASSKEY_EMAIL_KEY = \"passkey_email\";\n\nfunction openDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME);\n }\n };\n });\n}\n\n/**\n * Get the stored passkey email from IndexedDB\n */\nexport async function getPasskeyEmail(): Promise<string | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\nexport async function setPasskeyEmail(email: string): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(email, PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch {\n // Silently fail - passkey will still work, just won't remember email\n }\n}\n\n/**\n * Remove the passkey email from IndexedDB\n */\nexport async function clearPasskeyEmail(): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.delete(PASSKEY_EMAIL_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch {\n // Silently fail\n }\n}\n\n// ============================================================\n// DPoP (Demonstration of Proof-of-Possession) using ECDSA P-256\n// Per RFC 9449 - https://datatracker.ietf.org/doc/html/rfc9449\n// ============================================================\n\nconst DPOP_PRIVATE_KEY_STORAGE_KEY = \"dpop_private_key\";\nconst DPOP_PUBLIC_KEY_JWK_STORAGE_KEY = \"dpop_public_key_jwk\";\n\n/**\n * Minimal JWK for EC P-256 public key (only required fields per RFC 7517)\n */\nexport interface MinimalECPublicKeyJWK {\n kty: \"EC\";\n crv: \"P-256\";\n x: string;\n y: string;\n}\n\n/**\n * Create a minimal JWK from a full JWK (removes ext, key_ops, etc.)\n */\nexport function toMinimalJWK(jwk: JsonWebKey): MinimalECPublicKeyJWK {\n return {\n kty: \"EC\",\n crv: \"P-256\",\n x: jwk.x!,\n y: jwk.y!,\n };\n}\n\n/**\n * Calculate JWK Thumbprint (SHA-256) per RFC 7638\n * Uses canonical JSON with lexicographically ordered required members\n */\nexport async function calculateThumbprint(\n jwk: MinimalECPublicKeyJWK\n): Promise<string> {\n // Canonical JSON with required members in lexicographic order for EC keys\n const canonical = JSON.stringify({\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n y: jwk.y,\n });\n\n const hash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(canonical)\n );\n\n return arrayBufferToBase64url(hash);\n}\n\n/**\n * Store DPoP Private Key in IndexedDB\n */\nasync function storeDPoPPrivateKey(key: CryptoKey): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(key, DPOP_PRIVATE_KEY_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch (err) {\n console.error(\"Failed to store DPoP private key:\", err);\n }\n}\n\n/**\n * Store DPoP Public Key JWK in IndexedDB\n */\nasync function storeDPoPPublicKeyJWK(\n jwk: MinimalECPublicKeyJWK\n): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(jwk, DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n tx.oncomplete = () => db.close();\n });\n } catch (err) {\n console.error(\"Failed to store DPoP public key JWK:\", err);\n }\n}\n\n/**\n * Retrieve DPoP Private Key from IndexedDB\n */\nexport async function getDPoPKey(): Promise<CryptoKey | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(DPOP_PRIVATE_KEY_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\n/**\n * Retrieve DPoP Public Key JWK from IndexedDB\n */\nexport async function getDPoPPublicKeyJWK(): Promise<MinimalECPublicKeyJWK | null> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n tx.oncomplete = () => db.close();\n });\n } catch {\n return null;\n }\n}\n\n/**\n * Clear stored DPoP Keys from IndexedDB\n */\nexport async function clearDPoPKey(): Promise<void> {\n try {\n const db = await openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n store.delete(DPOP_PRIVATE_KEY_STORAGE_KEY);\n store.delete(DPOP_PUBLIC_KEY_JWK_STORAGE_KEY);\n tx.onerror = () => reject(tx.error);\n tx.oncomplete = () => {\n db.close();\n resolve();\n };\n });\n } catch {\n // Silently fail\n }\n}\n\n/**\n * Generate a new ECDSA P-256 Key Pair for DPoP.\n * Stores both Private Key (CryptoKey) and Public Key (JWK) in IndexedDB.\n * Returns minimal Public Key JWK and its Thumbprint for backend transmission.\n */\nexport async function generateDPoPKeyPair(): Promise<{\n publicKey: MinimalECPublicKeyJWK;\n thumbprint: string;\n}> {\n // 1. Generate Key Pair\n const keyPair = await crypto.subtle.generateKey(\n {\n name: \"ECDSA\",\n namedCurve: \"P-256\",\n },\n false, // Private key is non-extractable\n [\"sign\", \"verify\"]\n );\n\n // 2. Export Public Key as full JWK, then convert to minimal\n const fullJwk = await crypto.subtle.exportKey(\"jwk\", keyPair.publicKey);\n const minimalJwk = toMinimalJWK(fullJwk);\n\n // 3. Calculate Thumbprint\n const thumbprint = await calculateThumbprint(minimalJwk);\n\n // 4. Store both keys in IndexedDB\n await storeDPoPPrivateKey(keyPair.privateKey);\n await storeDPoPPublicKeyJWK(minimalJwk);\n\n return { publicKey: minimalJwk, thumbprint };\n}\n\n/**\n * Generate a DPoP proof JWT using ECDSA P-256 (ES256)\n * Per RFC 9449 Section 4.2\n *\n * @param httpMethod - HTTP method (GET, POST, etc.)\n * @param httpUri - Full URL of the request (without query/fragment for htu)\n * @param accessToken - Optional access token to bind (adds ath claim)\n */\nexport async function generateDPoPProof(\n httpMethod: string,\n httpUri: string,\n accessToken?: string\n): Promise<string | null> {\n try {\n const privateKey = await getDPoPKey();\n const publicKeyJwk = await getDPoPPublicKeyJWK();\n\n if (!privateKey || !publicKeyJwk) return null;\n\n // DPoP header per RFC 9449 Section 4.2\n // MUST include typ, alg, and jwk (public key)\n const header = {\n typ: \"dpop+jwt\",\n alg: \"ES256\",\n jwk: publicKeyJwk, // Public key in JWK format\n };\n\n // Parse URL to get htu without query/fragment\n // Use window.location.origin as base for relative URLs\n const url = new URL(\n httpUri,\n typeof window !== \"undefined\" ? window.location.origin : undefined\n );\n const htu = `${url.origin}${url.pathname}`;\n\n // DPoP payload per RFC 9449 Section 4.2\n const payload: Record<string, string | number> = {\n jti: crypto.randomUUID(),\n htm: httpMethod.toUpperCase(),\n htu: htu,\n iat: Math.floor(Date.now() / 1000),\n };\n\n if (accessToken) {\n const tokenBytes = new TextEncoder().encode(accessToken);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", tokenBytes);\n payload.ath = arrayBufferToBase64url(hashBuffer);\n }\n\n const encodedHeader = arrayBufferToBase64url(\n new TextEncoder().encode(JSON.stringify(header)).buffer as ArrayBuffer\n );\n const encodedPayload = arrayBufferToBase64url(\n new TextEncoder().encode(JSON.stringify(payload)).buffer as ArrayBuffer\n );\n\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n const signatureBuffer = await crypto.subtle.sign(\n {\n name: \"ECDSA\",\n hash: { name: \"SHA-256\" },\n },\n privateKey,\n new TextEncoder().encode(signatureInput)\n );\n const signature = arrayBufferToBase64url(signatureBuffer);\n\n return `${encodedHeader}.${encodedPayload}.${signature}`;\n } catch (err) {\n console.error(\"Failed to generate DPoP proof:\", err);\n return null;\n }\n}\n\n/**\n * Check if DPoP is enabled (Keys are stored)\n */\nexport async function isDPoPEnabled(): Promise<boolean> {\n const key = await getDPoPKey();\n return key !== null;\n}\n\n // Legacy export for backward compatibility\nexport const storeDPoPKey = storeDPoPPrivateKey;\n\nconst WebAuthn = {\n isWebAuthnSupported,\n isConditionalUISupported,\n arrayBufferToBase64,\n base64ToArrayBuffer,\n arrayBufferToBase64url,\n base64urlToArrayBuffer,\n stringToArrayBuffer,\n uint8ArrayToString,\n getPasskeyEmail,\n setPasskeyEmail,\n clearPasskeyEmail,\n toMinimalJWK,\n calculateThumbprint,\n getDPoPKey,\n getDPoPPublicKeyJWK,\n clearDPoPKey,\n generateDPoPKeyPair,\n generateDPoPProof,\n isDPoPEnabled,\n storeDPoPKey,\n};\n\n// if (typeof window !== \"undefined\") {\n// (window as unknown as { WebAuthn: typeof WebAuthn }).WebAuthn = WebAuthn;\n// }\n\n// var global: any = window || global;\n// global.WebAuthn = WebAuthn;\n// global.webauthnReady = () => {\n// document.dispatchEvent(new CustomEvent(\"webauthnReady\"));\n// };","import {\n arrayBufferToBase64,\n generateDPoPKeyPair,\n generateDPoPProof,\n stringToArrayBuffer,\n clearDPoPKey,\n base64ToArrayBuffer,\n} from \"./webauthn\";\n\ninterface AuthSDKConfig {\n apiKey?: string;\n}\n\nconst LOCALSTORAGE_TOKEN_KEY = \"postex-auth-token\";\n\ntype AuthStatusType = \"no_session\" | \"session_found\" | \"webauthn_ready\";\n\ninterface AuthStatusResponse {\n status: AuthStatusType;\n email?: string;\n webauthn?: boolean;\n challenge?: string;\n credentialIds?: string[];\n rp?: { name: string; host: string };\n}\n\n/** Response from POST /auth/initiate */\ntype InitiateAuthStatusType = \"webauthn_challenge\" | \"otp_sent\";\n\ninterface InitiateAuthResponse {\n status: InitiateAuthStatusType;\n challenge?: string;\n credentialIds?: string[];\n rp?: { name: string; host: string };\n}\n\ninterface OTPVerifyResponse {\n access_token: string;\n id_token: string;\n refresh_token: string;\n expires_in: number;\n token_type: string;\n verified: boolean;\n email: string;\n [key: string]: any;\n}\n\ninterface PasskeyRegistrationChallenge {\n challenge: string;\n rp: { name: string; id: string };\n user: { id: string; name: string; displayName: string };\n pubKeyCredParams?: Array<{ type: string; alg: number }>;\n authenticatorSelection?: AuthenticatorSelectionCriteria;\n timeout?: number;\n attestation?: AttestationConveyancePreference;\n /** Existing credential IDs to exclude (prevents duplicate registration) */\n excludeCredentials?: Array<{\n id: string;\n type: \"public-key\";\n transports?: AuthenticatorTransport[];\n }>;\n}\n\ninterface PasskeyRegisterResponse {\n registered: boolean;\n [key: string]: any;\n}\n\ninterface PasskeyStatusResponse {\n credentialId?: string;\n hasCredentials: boolean;\n [key: string]: any;\n}\n\ninterface AuthResponse {\n access_token: string;\n refresh_token: string;\n id_token?: string;\n email: string;\n name: string;\n expiresIn?: number;\n tokenType?: string;\n [key: string]: any;\n}\n\n/** Response from POST /auth/refresh */\ninterface RefreshTokenResponse {\n access_token: string;\n id_token?: string;\n token_type: string;\n expires_in: number;\n}\n\nconst DEFAULT_BASE_URL = \"http://localhost:3200\";\n\nexport class AuthSDKFetchError extends Error {\n response: { status: number; data?: any };\n\n constructor(status: number, data?: any, message?: string) {\n super(message ?? `Request failed with status ${status}`);\n this.response = { status, data };\n this.name = \"AuthSDKFetchError\";\n }\n}\n\nconst ID_TOKEN_KEY = \"auth_sdk_id_token\";\nconst REFRESH_TOKEN_KEY = \"auth_sdk_refresh_token\";\n\nexport class AuthSDK {\n private config: AuthSDKConfig;\n\n constructor(config: AuthSDKConfig) {\n this.config = config;\n }\n\n private buildUrl(path: string, params?: Record<string, string>): string {\n const base = DEFAULT_BASE_URL.replace(/\\/$/, \"\");\n const pathNorm = path.startsWith(\"/\") ? path : `/${path}`;\n const url = `${base}${pathNorm}`;\n if (!params || Object.keys(params).length === 0) return url;\n const search = new URLSearchParams(params).toString();\n return `${url}?${search}`;\n }\n\n private async request<T>(\n method: string,\n path: string,\n options?: {\n body?: any;\n params?: Record<string, string>;\n headers?: Record<string, string>;\n }\n ): Promise<{ data: T }> {\n const url = this.buildUrl(path, options?.params);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"X-API-Key\": this.config.apiKey ?? \"\",\n ...options?.headers,\n };\n\n const init: RequestInit = {\n method,\n credentials: \"include\",\n headers,\n };\n if (options?.body !== undefined && options?.body !== null) {\n init.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, init);\n\n if (!response.ok) {\n let data: any;\n try {\n const text = await response.text();\n data = text ? JSON.parse(text) : undefined;\n } catch {\n data = undefined;\n }\n if (response.status === 401) {\n await this.clearTokens();\n }\n throw new AuthSDKFetchError(response.status, data);\n }\n\n const text = await response.text();\n const data = text ? JSON.parse(text) : {};\n return { data };\n }\n\n /**\n * Returns auth headers (Authorization + DPoP) for the given request.\n * Use this to attach auth to your own HTTP client (e.g. axios request interceptor).\n * @param method - HTTP method (e.g. \"GET\", \"POST\")\n * @param url - Full request URL\n */\n async getRequestAuthHeaders(\n method: string,\n url: string\n ): Promise<Record<string, string>> {\n const token = localStorage.getItem(LOCALSTORAGE_TOKEN_KEY);\n if (!token) return {};\n const fullUrl = url.startsWith(\"http\") ? url : `${DEFAULT_BASE_URL}${url}`;\n const dpopProof = await generateDPoPProof(\n method.toUpperCase(),\n fullUrl,\n token\n );\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n if (dpopProof) headers[\"DPoP\"] = dpopProof;\n return headers;\n }\n\n /**\n * GET /auth/status - Check if client has trusted device session and what auth method is available.\n * Returns no_session | session_found | webauthn_ready per PostEx Auth BFF spec.\n */\n async getStatus(email: string): Promise<AuthStatusResponse> {\n const response = await this.request<unknown>(\"GET\", \"/auth/status\", {\n params: { email },\n });\n return (response.data as any).data ?? response.data;\n }\n\n /**\n * POST /auth/initiate - Unified entry: returns webauthn_challenge or otp_sent.\n * Sets auth_session cookie when otp_sent.\n */\n async initiateAuth(email: string): Promise<InitiateAuthResponse> {\n const response = await this.request<unknown>(\"POST\", \"/auth/initiate\", {\n body: { email },\n });\n const data = (response.data as any).data ?? response.data;\n return {\n status: data.status,\n challenge: data.challenge,\n credentialIds: data.credentialIds,\n rp: data.rp,\n };\n }\n\n /**\n * POST /otp/verify - Verifies the OTP code entered by the user.\n * Stores tokens from the response.\n */\n async verifyOTP(otp: string): Promise<OTPVerifyResponse> {\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/otp/verify`\n );\n\n const response = await this.request<unknown>(\"POST\", \"/otp/verify\", {\n body: { otp },\n headers: dpopProof ? { DPoP: dpopProof } : {},\n });\n const data = (response.data as any).data ?? response.data;\n\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.access_token ?? result.accessToken ?? result.AccessToken;\n const refreshToken =\n result.refresh_token ?? result.refreshToken ?? result.RefreshToken;\n const idToken = result.id_token ?? result.idToken ?? result.IdToken;\n const expiresIn =\n result.expires_in ?? result.expiresIn ?? result.ExpiresIn ?? 3600;\n const tokenType =\n result.token_type ?? result.tokenType ?? result.TokenType ?? \"Bearer\";\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: expiresIn ?? 3600,\n tokenType: tokenType ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken ?? \"\",\n expires_in: expiresIn,\n token_type: tokenType,\n verified: result.verified ?? result.Verified ?? true,\n email: result.email ?? result.Email ?? \"\",\n ...result,\n };\n }\n\n /**\n * GET /magic-link - Verify a magic link token.\n * Sets auth_session cookie on success.\n */\n async verifyMagicLink(token: string, email: string): Promise<void> {\n await this.request(\"GET\", \"/verify/magic-link\", {\n params: { token, email, redirect_mode: \"frontend\" },\n });\n }\n\n /**\n * POST /magic-link/complete - Complete magic link authentication.\n * Requires auth_session cookie set by verifyMagicLink.\n * Stores tokens from the response.\n */\n async completeMagicLink(): Promise<OTPVerifyResponse> {\n const response = await this.request<unknown>(\n \"POST\",\n \"/verify/magic-link/complete\",\n {\n body: {},\n }\n );\n const data = (response.data as any).data ?? response.data;\n\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.access_token ?? result.accessToken ?? result.AccessToken;\n const refreshToken =\n result.refresh_token ?? result.refreshToken ?? result.RefreshToken;\n const idToken = result.id_token ?? result.idToken ?? result.IdToken;\n const expiresIn =\n result.expires_in ?? result.expiresIn ?? result.ExpiresIn ?? 3600;\n const tokenType =\n result.token_type ?? result.tokenType ?? result.TokenType ?? \"Bearer\";\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: expiresIn ?? 3600,\n tokenType: tokenType ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken ?? \"\",\n expires_in: expiresIn,\n token_type: tokenType,\n verified: result.verified ?? result.Verified ?? true,\n email: result.email ?? result.Email ?? \"\",\n ...result,\n };\n }\n\n async initiatePasskeyRegistration(): Promise<PasskeyRegistrationChallenge> {\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/initiate/challenge\",\n {\n body: {},\n }\n );\n return (response.data as any).data ?? response.data;\n }\n\n async registerPasskey(email: string): Promise<PasskeyRegisterResponse> {\n const challenge = await this.initiatePasskeyRegistration();\n let userIdBuffer: ArrayBuffer;\n if (challenge?.user?.id) {\n try {\n userIdBuffer = base64ToArrayBuffer(challenge.user.id);\n } catch {\n userIdBuffer = stringToArrayBuffer(challenge.user.id);\n }\n } else {\n userIdBuffer = stringToArrayBuffer(email);\n }\n\n const pubKeyCredParams = (\n challenge.pubKeyCredParams ?? [\n { type: \"public-key\", alg: -7 },\n { type: \"public-key\", alg: -257 },\n ]\n ).map((param) => ({\n type: \"public-key\" as const,\n alg: param.alg,\n }));\n\n const excludeCredentials: PublicKeyCredentialDescriptor[] | undefined =\n challenge.excludeCredentials?.map((cred) => ({\n type: \"public-key\" as const,\n id: base64ToArrayBuffer(cred.id),\n transports: cred.transports,\n }));\n\n const createOptions: PublicKeyCredentialCreationOptions = {\n challenge: base64ToArrayBuffer(challenge.challenge),\n rp: {\n name: challenge.rp?.name ?? \"XPay\",\n id: challenge.rp?.id ?? window.location.hostname,\n },\n user: {\n id: userIdBuffer,\n name: challenge.user?.name ?? email,\n displayName: challenge.user?.displayName ?? email,\n },\n pubKeyCredParams,\n timeout: challenge.timeout ?? 60000,\n attestation: challenge.attestation ?? \"none\",\n authenticatorSelection: challenge.authenticatorSelection ?? {\n residentKey: \"required\",\n userVerification: \"required\",\n },\n };\n\n const credential = (await navigator.credentials.create({\n publicKey: createOptions,\n })) as PublicKeyCredential;\n\n if (!credential) throw new Error(\"Credential creation failed\");\n const attResp = credential.response as AuthenticatorAttestationResponse;\n const payload = {\n clientDataJSON: arrayBufferToBase64(attResp.clientDataJSON),\n attestationObject: arrayBufferToBase64(attResp.attestationObject),\n rawId: arrayBufferToBase64(credential.rawId as ArrayBuffer),\n }; \n if (!payload.rawId) throw new Error(\"Raw ID is required\");\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/webauthn/register/challenge`\n );\n\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/register/challenge\",\n {\n body: payload,\n headers: dpopProof ? { DPoP: dpopProof } : {},\n }\n );\n\n return (response.data as any).data ?? response.data;\n }\n\n /**\n * POST /webauthn/authenticate/challenge - Authenticate with passkey.\n */\n async authenticateWithPasskey({\n challenge,\n rp,\n credentialIds,\n }: {\n challenge: string;\n rp: { name: string; host: string };\n credentialIds: string[];\n }): Promise<AuthResponse> {\n const assertion = (await navigator.credentials.get({\n publicKey: {\n challenge: base64ToArrayBuffer(challenge),\n rpId: rp?.host ?? undefined,\n allowCredentials: credentialIds.map((id: string) => ({\n type: \"public-key\" as const,\n id: base64ToArrayBuffer(id),\n // Hint browser about possible transports for faster authenticator discovery\n // transports: [\"internal\", \"hybrid\"] as AuthenticatorTransport[],\n })),\n timeout: 60000,\n userVerification: \"required\",\n },\n })) as PublicKeyCredential;\n\n if (!assertion) throw new Error(\"Authentication failed\");\n const assertionResponse =\n assertion.response as AuthenticatorAssertionResponse;\n const payload = {\n clientDataJSON: arrayBufferToBase64(assertionResponse.clientDataJSON),\n authenticatorData: arrayBufferToBase64(\n assertionResponse.authenticatorData\n ),\n signature: arrayBufferToBase64(assertionResponse.signature),\n rawId: arrayBufferToBase64(assertion.rawId as ArrayBuffer),\n userHandle: assertionResponse.userHandle\n ? arrayBufferToBase64(assertionResponse.userHandle)\n : \"\",\n };\n\n await generateDPoPKeyPair();\n const dpopProof = await generateDPoPProof(\n \"POST\",\n `${DEFAULT_BASE_URL}/webauthn/authenticate/challenge`\n );\n\n const response = await this.request<unknown>(\n \"POST\",\n \"/webauthn/authenticate/challenge\",\n {\n body: payload,\n headers: dpopProof ? { DPoP: dpopProof } : {},\n }\n );\n\n const data = (response.data as any).data ?? response.data;\n const result = data.AuthenticationResult ?? data;\n const accessToken =\n result.AccessToken ?? result.accessToken ?? result.access_token;\n const refreshToken =\n result.RefreshToken ?? result.refreshToken ?? result.refresh_token;\n const idToken = result.IdToken ?? result.idToken ?? result.id_token;\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n refreshToken: refreshToken ?? \"\",\n idToken: idToken ?? \"\",\n expiresIn: result.expiresIn ?? result.ExpiresIn ?? 3600,\n tokenType: result.tokenType ?? result.token_type ?? \"Bearer\",\n });\n }\n\n return {\n access_token: accessToken,\n refresh_token: refreshToken ?? \"\",\n id_token: idToken,\n email: result.email,\n name: result.name ?? result.userName,\n expiresIn: result.expiresIn ?? result.ExpiresIn,\n tokenType: result.tokenType ?? result.token_type,\n ...result,\n };\n }\n /**\n * GET /webauthn/credentials/:username - Get user's passkey status.\n */\n async getPasskeyStatus(username: string): Promise<PasskeyStatusResponse> {\n const encoded = encodeURIComponent(username);\n const path = `/webauthn/credentials/${encoded}`;\n const signed = await this.signRequest(\"GET\", path);\n const response = await this.request<unknown>(\"GET\", path, {\n headers: signed.headers as Record<string, string>,\n });\n const data = (response.data as any).data ?? response.data;\n return {\n ...data,\n hasCredentials: Boolean(data.hasCredentials ?? data.credentialId),\n };\n }\n\n /**\n * DELETE /webauthn/credentials/:username - Remove passkey.\n */\n async removePasskey(username: string): Promise<void> {\n const encoded = encodeURIComponent(username);\n const path = `/webauthn/credentials/${encoded}`;\n const signed = await this.signRequest(\"DELETE\", path);\n await this.request(\"DELETE\", path, {\n headers: signed.headers as Record<string, string>,\n });\n }\n\n /**\n * Signs a request with DPoP and Authorization headers (internal use).\n */\n async signRequest(\n method: string,\n url: string,\n config: any = {}\n ): Promise<any> {\n const fullUrl = url.startsWith(\"http\") ? url : `${DEFAULT_BASE_URL}${url}`;\n const authHeaders = await this.getRequestAuthHeaders(method, fullUrl);\n return { ...config, headers: { ...config.headers, ...authHeaders } };\n }\n\n /**\n * Replaces native fetch or Axios with a DPoP-signed version.\n */\n async authenticatedFetch(\n input: RequestInfo | URL,\n init?: RequestInit\n ): Promise<Response> {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n const method = init?.method || \"GET\";\n\n const signedInit = await this.signRequest(method, url, {\n headers: init?.headers,\n });\n return fetch(input, { ...init, headers: signedInit.headers });\n }\n\n /**\n * Store tokens from /webauthn/authenticate (per spec: sessionStorage preferred).\n */\n async storeTokens(tokens: {\n accessToken: string;\n refreshToken?: string;\n idToken?: string;\n expiresIn?: number;\n tokenType?: string;\n }): Promise<void> {\n localStorage.setItem(LOCALSTORAGE_TOKEN_KEY, tokens.accessToken);\n if (tokens.refreshToken) {\n localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken);\n }\n if (tokens.idToken) {\n localStorage.setItem(ID_TOKEN_KEY, tokens.idToken);\n }\n }\n\n /**\n * Clear stored tokens (call on logout).\n */\n async clearTokens(): Promise<void> {\n localStorage.removeItem(LOCALSTORAGE_TOKEN_KEY);\n localStorage.removeItem(ID_TOKEN_KEY);\n localStorage.removeItem(REFRESH_TOKEN_KEY);\n }\n\n /**\n * POST /auth/refresh - Refresh access token using server-stored refresh token.\n * Requires trusted device cookie (td). Refresh token is stored server-side.\n * Rate limit: 10 requests per minute.\n */\n async refreshToken(): Promise<RefreshTokenResponse> {\n const response = await this.request<unknown>(\"POST\", \"/auth/refresh\", {\n body: {},\n });\n const data = (response.data as any).data ?? response.data;\n\n const accessToken = data.access_token;\n const idToken = data.id_token ?? \"\";\n const tokenType = data.token_type ?? \"Bearer\";\n const expiresIn = data.expires_in ?? 3600;\n\n if (accessToken) {\n await this.storeTokens({\n accessToken,\n idToken,\n expiresIn,\n tokenType,\n });\n }\n\n return {\n access_token: accessToken,\n id_token: idToken,\n token_type: tokenType,\n expires_in: expiresIn,\n };\n }\n\n /**\n * POST /auth/logout - Logout from the current device.\n * Revokes the current token and trusted device, then clears local tokens.\n */\n async logout(): Promise<void> {\n try {\n const token = await this.getAccessToken();\n const headers: Record<string, string> = {};\n if (token) {\n headers[\"Authorization\"] = `Bearer ${token}`;\n }\n await this.request(\"POST\", \"/auth/logout\", { body: {}, headers });\n clearDPoPKey();\n } catch {\n // Silently fail - proceed with local cleanup\n }\n await this.clearTokens();\n }\n\n async getAccessToken(): Promise<string | null> {\n return localStorage.getItem(LOCALSTORAGE_TOKEN_KEY);\n }\n}\n\n// Expose SDK on global window for use by other JS projects (e.g. script tag / iframe)\n// if (typeof window !== \"undefined\") {\n// (window as unknown as { AuthSDK: typeof AuthSDK }).AuthSDK = AuthSDK;\n// }\n\n// var global: any = window || global;\n// global.AuthSDK = AuthSDK;\n// global.authsdkReady = () => {\n// document.dispatchEvent(new CustomEvent(\"authsdkReady\"));\n// };\n"],"names":["isWebAuthnSupported","isConditionalUISupported","arrayBufferToBase64","buffer","bytes","binary","i","base64ToArrayBuffer","base64","cleaned","pad","padded","arrayBufferToBase64url","isUUID","str","uuidToArrayBuffer","uuid","hex","base64urlToArrayBuffer","input","stringToArrayBuffer","uint8ArrayToString","arr","DB_NAME","DB_VERSION","STORE_NAME","PASSKEY_EMAIL_KEY","openDB","resolve","reject","request","db","getPasskeyEmail","tx","setPasskeyEmail","email","clearPasskeyEmail","DPOP_PRIVATE_KEY_STORAGE_KEY","DPOP_PUBLIC_KEY_JWK_STORAGE_KEY","toMinimalJWK","jwk","calculateThumbprint","canonical","hash","storeDPoPPrivateKey","key","err","storeDPoPPublicKeyJWK","getDPoPKey","getDPoPPublicKeyJWK","clearDPoPKey","store","generateDPoPKeyPair","keyPair","fullJwk","minimalJwk","thumbprint","generateDPoPProof","httpMethod","httpUri","accessToken","privateKey","publicKeyJwk","header","url","htu","payload","tokenBytes","hashBuffer","encodedHeader","encodedPayload","signatureInput","signatureBuffer","signature","isDPoPEnabled","storeDPoPKey","LOCALSTORAGE_TOKEN_KEY","DEFAULT_BASE_URL","AuthSDKFetchError","status","data","message","ID_TOKEN_KEY","REFRESH_TOKEN_KEY","AuthSDK","config","path","params","base","pathNorm","search","method","options","headers","init","response","text","token","fullUrl","dpopProof","otp","result","refreshToken","idToken","expiresIn","tokenType","challenge","userIdBuffer","pubKeyCredParams","param","cred","createOptions","credential","attResp","rp","credentialIds","assertion","id","assertionResponse","username","signed","authHeaders","signedInit","tokens"],"mappings":"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"}
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "postex-auth-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "PostEx Auth SDK for authentication flows: OTP, magic links, passkeys, and token management",
|
|
5
|
+
"main": "./dist/postex-auth-sdk.umd.js",
|
|
6
|
+
"module": "./dist/postex-auth-sdk.es.js",
|
|
7
|
+
"types": "./dist/main.d.ts",
|
|
8
|
+
"files": ["dist"],
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/main.d.ts",
|
|
12
|
+
"import": "./dist/postex-auth-sdk.es.js",
|
|
13
|
+
"require": "./dist/postex-auth-sdk.umd.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"keywords": ["auth", "webauthn", "passkey", "otp", "sdk", "postex"],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": ""
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"dev": "vite",
|
|
25
|
+
"build": "tsc && vite build",
|
|
26
|
+
"preview": "vite preview"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"typescript": "~5.9.3",
|
|
30
|
+
"vite": "^7.3.1"
|
|
31
|
+
}
|
|
32
|
+
}
|