@cemiar/auth-sdk 1.0.2 → 1.0.4
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
CHANGED
|
@@ -52,6 +52,19 @@ const jobs = await api.get("/api/jobs");
|
|
|
52
52
|
authClient.attachInterceptors(existingAxiosInstance);
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
#### Handling the Microsoft callback
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const params = Object.fromEntries(new URLSearchParams(window.location.search));
|
|
59
|
+
const user = authClient.handleRedirectMicrosoftCallback(params);
|
|
60
|
+
|
|
61
|
+
if (user) {
|
|
62
|
+
history.replaceState(null, "", "/dashboard");
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`handleRedirectMicrosoftCallback` stores the returned access token, infers the login method for future logouts, and gives you the signed-in user details. Call it once on your redirect page, then clean up the query string if needed.
|
|
67
|
+
|
|
55
68
|
#### Token storage hooks
|
|
56
69
|
|
|
57
70
|
By default the client stores tokens in `localStorage`. Override storage to customize behaviour:
|
|
@@ -74,6 +87,20 @@ const authClient = createCemiarAuthClient({
|
|
|
74
87
|
});
|
|
75
88
|
```
|
|
76
89
|
|
|
90
|
+
#### Logging out
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
await authClient.logout();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Logout automatically detects whether the user signed in with Microsoft or email and routes to the matching Cemiar Auth endpoint. Override behaviour with the optional flags:
|
|
97
|
+
|
|
98
|
+
- `redirectUrl`: override the post-logout redirect (defaults to `logoutRedirectUrl` from the constructor)
|
|
99
|
+
- `performRedirect`: set to `false` to stay on the page and only clear the server session
|
|
100
|
+
- `clearToken`: set to `false` to retain the locally cached access token
|
|
101
|
+
|
|
102
|
+
You can still specify `method: "microsoft" | "emailCode"` if you need to force a flow.
|
|
103
|
+
|
|
77
104
|
### Backend (Hapi)
|
|
78
105
|
|
|
79
106
|
```ts
|
|
@@ -20,7 +20,7 @@ export declare class CemiarAuthClient implements CemiarAuthClientInstance {
|
|
|
20
20
|
handleRedirectMicrosoftCallback(routeQueryData: Record<string, string>): UserInfo | null;
|
|
21
21
|
getMicrosoftLoginUrl(extraParams?: Record<string, string>): string;
|
|
22
22
|
refreshToken(): Promise<AuthTokens>;
|
|
23
|
-
logout(
|
|
23
|
+
logout(_options?: LogoutOptions): Promise<void>;
|
|
24
24
|
createApiClient(options: CreateApiClientOptions): AxiosInstance;
|
|
25
25
|
attachInterceptors(instance: AxiosInstance): AxiosInstance;
|
|
26
26
|
private addAuthHeader;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { createDefaultTokenStorage } from "./Storage.js";
|
|
3
|
-
import { normalizeBaseUrl, isBrowser,
|
|
3
|
+
import { normalizeBaseUrl, isBrowser, tokenToClaimBrowser } from "../shared/Utils.js";
|
|
4
4
|
const LOGIN_METHOD_STORAGE_KEY = "cemiar-auth-login-method";
|
|
5
5
|
function parseAuds(auds) {
|
|
6
6
|
return auds.map(a => a.trim()).filter(Boolean);
|
|
@@ -18,7 +18,7 @@ export class CemiarAuthClient {
|
|
|
18
18
|
var _a, _b, _c;
|
|
19
19
|
this.storage = createDefaultTokenStorage();
|
|
20
20
|
this.refreshPromise = null;
|
|
21
|
-
this.baseUrl = normalizeBaseUrl(config.baseUrl || "http://localhost:3000/auth"
|
|
21
|
+
this.baseUrl = normalizeBaseUrl(config.baseUrl || "http://localhost:3000") + "/auth";
|
|
22
22
|
this.tenantId = config.tenantId;
|
|
23
23
|
this.auds = parseAuds(config.auds);
|
|
24
24
|
this.redirectUrl =
|
|
@@ -62,7 +62,7 @@ export class CemiarAuthClient {
|
|
|
62
62
|
const accessToken = extractAccessToken(data);
|
|
63
63
|
this.setAccessToken(accessToken);
|
|
64
64
|
this.persistLoginMethod("emailCode");
|
|
65
|
-
const claim =
|
|
65
|
+
const claim = tokenToClaimBrowser(accessToken);
|
|
66
66
|
return {
|
|
67
67
|
email: claim.sub,
|
|
68
68
|
displayName: claim.displayName
|
|
@@ -73,7 +73,7 @@ export class CemiarAuthClient {
|
|
|
73
73
|
if (token) {
|
|
74
74
|
this.setAccessToken(token);
|
|
75
75
|
this.persistLoginMethod("microsoft");
|
|
76
|
-
const claim =
|
|
76
|
+
const claim = tokenToClaimBrowser(token);
|
|
77
77
|
return {
|
|
78
78
|
email: claim.sub,
|
|
79
79
|
displayName: claim.displayName
|
|
@@ -99,29 +99,9 @@ export class CemiarAuthClient {
|
|
|
99
99
|
this.setAccessToken(accessToken);
|
|
100
100
|
return { accessToken };
|
|
101
101
|
}
|
|
102
|
-
async logout(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
loginMethod = this.getCurrentLoginMethod();
|
|
106
|
-
if (options.clearToken !== false) {
|
|
107
|
-
this.setAccessToken(null);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
const redirectUrl = options.redirectUrl || this.logoutRedirectUrl;
|
|
111
|
-
const logoutPath = loginMethod === "microsoft" ? "/microsoft/logout" : "/logout";
|
|
112
|
-
const logoutUrl = redirectUrl
|
|
113
|
-
? `${this.baseUrl}${logoutPath}?redirectUrl=${encodeURIComponent(redirectUrl)}`
|
|
114
|
-
: `${this.baseUrl}${logoutPath}`;
|
|
115
|
-
try {
|
|
116
|
-
if (options.performRedirect === false || !isBrowser) {
|
|
117
|
-
await axios.post(`${this.baseUrl}/logout`, {}, { withCredentials: true });
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
window.location.href = logoutUrl;
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
// ignore network errors during logout
|
|
124
|
-
}
|
|
102
|
+
async logout(_options = {}) {
|
|
103
|
+
await axios.post(`${this.baseUrl}/logout`, {}, { withCredentials: true });
|
|
104
|
+
this.setAccessToken(null);
|
|
125
105
|
}
|
|
126
106
|
createApiClient(options) {
|
|
127
107
|
var _a;
|
package/dist/shared/Utils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Claim } from "./models/Claim.js";
|
|
2
2
|
export declare function normalizeBaseUrl(url: string): string;
|
|
3
3
|
export declare function tokenToClaim(token: string): Claim;
|
|
4
|
+
export declare function tokenToClaimBrowser(token: string): Claim;
|
|
4
5
|
export declare const isBrowser: boolean;
|
package/dist/shared/Utils.js
CHANGED
|
@@ -10,4 +10,10 @@ export function tokenToClaim(token) {
|
|
|
10
10
|
const parsed = JSON.parse(decoded);
|
|
11
11
|
return parsed;
|
|
12
12
|
}
|
|
13
|
+
export function tokenToClaimBrowser(token) {
|
|
14
|
+
const payload = token.split(".")[1];
|
|
15
|
+
const decoded = atob(payload);
|
|
16
|
+
const parsed = JSON.parse(decoded);
|
|
17
|
+
return parsed;
|
|
18
|
+
}
|
|
13
19
|
export const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
|