azirid-react 0.13.0 → 0.13.2
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 +11 -9
- package/dist/index.cjs +35 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +35 -7
- package/dist/index.js.map +1 -1
- package/dist/next-proxy.cjs +2 -1
- package/dist/next-proxy.cjs.map +1 -1
- package/dist/next-proxy.js +2 -1
- package/dist/next-proxy.js.map +1 -1
- package/dist/next.cjs +2 -1
- package/dist/next.cjs.map +1 -1
- package/dist/next.js +2 -1
- package/dist/next.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1381,29 +1381,31 @@ The Azirid dashboard lets admins click "Sign in as user" to impersonate any end
|
|
|
1381
1381
|
|
|
1382
1382
|
**How it works:**
|
|
1383
1383
|
1. Admin clicks "Sign in as user" in the Azirid dashboard
|
|
1384
|
-
2. Dashboard generates a one-time code (valid for
|
|
1385
|
-
3. Your app renders `<HandoffCallback>`, which
|
|
1386
|
-
4.
|
|
1384
|
+
2. Dashboard generates a one-time handoff code (valid for 5 minutes) and redirects to your app at `/auth/handoff?code=<code>&api=<apiUrl>`
|
|
1385
|
+
3. Your app renders `<HandoffCallback>`, which exchanges the code for session tokens directly with the API
|
|
1386
|
+
4. Tokens are stored in `sessionStorage` — on redirect to `/`, `AziridProvider` picks them up automatically
|
|
1387
|
+
|
|
1388
|
+
> **`<HandoffCallback>` is fully standalone** — it does NOT depend on `AziridProvider`. It works even when the provider wraps the entire layout and its bootstrap would redirect to `/login`. No special route groups or layout changes needed.
|
|
1387
1389
|
|
|
1388
1390
|
**Setup — create the handoff page:**
|
|
1389
1391
|
|
|
1390
1392
|
```tsx
|
|
1391
1393
|
// app/auth/handoff/page.tsx
|
|
1392
1394
|
'use client'
|
|
1393
|
-
import { useRouter } from 'next/navigation'
|
|
1394
1395
|
import { HandoffCallback } from 'azirid-react'
|
|
1395
1396
|
|
|
1396
1397
|
export default function HandoffPage() {
|
|
1397
|
-
const router = useRouter()
|
|
1398
1398
|
return (
|
|
1399
1399
|
<HandoffCallback
|
|
1400
|
-
onSuccess={() =>
|
|
1401
|
-
onError={() =>
|
|
1400
|
+
onSuccess={() => window.location.href = '/'}
|
|
1401
|
+
onError={() => window.location.href = '/login'}
|
|
1402
1402
|
/>
|
|
1403
1403
|
)
|
|
1404
1404
|
}
|
|
1405
1405
|
```
|
|
1406
1406
|
|
|
1407
|
+
> **Important:** Use `window.location.href` (not `router.push()`) for redirects. This triggers a full page reload so `AziridProvider` re-bootstraps with the new tokens.
|
|
1408
|
+
|
|
1407
1409
|
**Props:**
|
|
1408
1410
|
|
|
1409
1411
|
| Prop | Type | Default | Description |
|
|
@@ -1413,10 +1415,10 @@ export default function HandoffPage() {
|
|
|
1413
1415
|
| `loadingText` | `string` | `"Signing you in..."` | Text shown while the exchange is in progress |
|
|
1414
1416
|
| `errorText` | `string` | `"Failed to complete sign-in. The link may have expired."` | Fallback error text |
|
|
1415
1417
|
|
|
1416
|
-
You can also call `client.exchangeHandoff(code)` directly if you prefer a headless approach:
|
|
1418
|
+
You can also call `client.exchangeHandoff(code, apiUrl)` directly if you prefer a headless approach:
|
|
1417
1419
|
|
|
1418
1420
|
```ts
|
|
1419
|
-
const { user } = await client.exchangeHandoff(code)
|
|
1421
|
+
const { user } = await client.exchangeHandoff(code, 'https://api.azirid.com/v1')
|
|
1420
1422
|
```
|
|
1421
1423
|
|
|
1422
1424
|
---
|
package/dist/index.cjs
CHANGED
|
@@ -386,7 +386,8 @@ function createAccessClient(config, appContext) {
|
|
|
386
386
|
}
|
|
387
387
|
return json;
|
|
388
388
|
}
|
|
389
|
-
async function exchangeHandoff(code) {
|
|
389
|
+
async function exchangeHandoff(code, apiUrl) {
|
|
390
|
+
const exchangeBase = apiUrl?.replace(/\/+$/, "") ?? baseUrl;
|
|
390
391
|
const headers = {
|
|
391
392
|
"Content-Type": "application/json",
|
|
392
393
|
...config.headers
|
|
@@ -396,7 +397,7 @@ function createAccessClient(config, appContext) {
|
|
|
396
397
|
}
|
|
397
398
|
const devId = getOrCreateDeviceId();
|
|
398
399
|
if (devId) headers["X-Device-Id"] = devId;
|
|
399
|
-
const res = await fetch(`${
|
|
400
|
+
const res = await fetch(`${exchangeBase}/users/auth/handoff/exchange`, {
|
|
400
401
|
method: "POST",
|
|
401
402
|
headers,
|
|
402
403
|
credentials: "include",
|
|
@@ -4007,7 +4008,6 @@ function HandoffCallback({
|
|
|
4007
4008
|
loadingText = "Signing you in...",
|
|
4008
4009
|
errorText = "Failed to complete sign-in. The link may have expired."
|
|
4009
4010
|
}) {
|
|
4010
|
-
const client = useAccessClient();
|
|
4011
4011
|
const [status, setStatus] = react.useState("loading");
|
|
4012
4012
|
const [errorMessage, setErrorMessage] = react.useState(null);
|
|
4013
4013
|
const attempted = react.useRef(false);
|
|
@@ -4016,21 +4016,49 @@ function HandoffCallback({
|
|
|
4016
4016
|
attempted.current = true;
|
|
4017
4017
|
const params = new URLSearchParams(window.location.search);
|
|
4018
4018
|
const code = params.get("code");
|
|
4019
|
+
const apiUrl = params.get("api");
|
|
4019
4020
|
if (!code) {
|
|
4020
4021
|
setStatus("error");
|
|
4021
4022
|
setErrorMessage("No handoff code provided");
|
|
4022
4023
|
onError?.(new Error("No handoff code provided"));
|
|
4023
4024
|
return;
|
|
4024
4025
|
}
|
|
4025
|
-
|
|
4026
|
-
|
|
4026
|
+
if (!apiUrl) {
|
|
4027
|
+
setStatus("error");
|
|
4028
|
+
setErrorMessage("No API URL provided");
|
|
4029
|
+
onError?.(new Error("No API URL in handoff link"));
|
|
4030
|
+
return;
|
|
4031
|
+
}
|
|
4032
|
+
const exchangeUrl = `${apiUrl.replace(/\/+$/, "")}/users/auth/handoff/exchange`;
|
|
4033
|
+
fetch(exchangeUrl, {
|
|
4034
|
+
method: "POST",
|
|
4035
|
+
headers: { "Content-Type": "application/json" },
|
|
4036
|
+
credentials: "include",
|
|
4037
|
+
body: JSON.stringify({ code })
|
|
4038
|
+
}).then(async (res) => {
|
|
4039
|
+
if (!res.ok) {
|
|
4040
|
+
const body = await res.json().catch(() => null);
|
|
4041
|
+
throw new Error(body?.error?.message ?? body?.message ?? "Handoff exchange failed");
|
|
4042
|
+
}
|
|
4043
|
+
return res.json();
|
|
4044
|
+
}).then((raw) => {
|
|
4045
|
+
const json = raw && typeof raw === "object" && "data" in raw && "meta" in raw ? raw.data : raw;
|
|
4046
|
+
json.at ?? json.accessToken;
|
|
4047
|
+
const refreshToken = json.rt ?? json.refreshToken;
|
|
4048
|
+
const csrfToken = json.xc ?? json.csrfToken;
|
|
4049
|
+
try {
|
|
4050
|
+
if (refreshToken) sessionStorage.setItem("__azrt", refreshToken);
|
|
4051
|
+
if (csrfToken) sessionStorage.setItem("__azxc", csrfToken);
|
|
4052
|
+
} catch {
|
|
4053
|
+
}
|
|
4054
|
+
onSuccess?.(json.user);
|
|
4027
4055
|
}).catch((err) => {
|
|
4028
4056
|
setStatus("error");
|
|
4029
4057
|
const error = err instanceof Error ? err : new Error("Handoff exchange failed");
|
|
4030
4058
|
setErrorMessage(error.message);
|
|
4031
4059
|
onError?.(error);
|
|
4032
4060
|
});
|
|
4033
|
-
}, [
|
|
4061
|
+
}, [onSuccess, onError]);
|
|
4034
4062
|
if (status === "error") {
|
|
4035
4063
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: wrapperStyle, children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: { ...messageStyle2, color: "#ef4444" }, children: errorMessage || errorText }) });
|
|
4036
4064
|
}
|
|
@@ -4847,7 +4875,7 @@ function usePasswordToggle() {
|
|
|
4847
4875
|
}
|
|
4848
4876
|
|
|
4849
4877
|
// src/index.ts
|
|
4850
|
-
var SDK_VERSION = "0.13.
|
|
4878
|
+
var SDK_VERSION = "0.13.2";
|
|
4851
4879
|
|
|
4852
4880
|
exports.AuthForm = AuthForm;
|
|
4853
4881
|
exports.AziridProvider = AziridProvider;
|