@loka-sms/sso 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/useOAuthCallback.js +19 -16
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -1
- package/dist/oauthRedirect.d.ts +8 -0
- package/dist/oauthRedirect.js +35 -0
- package/package.json +1 -1
|
@@ -54,7 +54,13 @@ function useOAuthCallback(input) {
|
|
|
54
54
|
method: 'POST',
|
|
55
55
|
headers: { 'Content-Type': 'application/json' },
|
|
56
56
|
credentials: 'include',
|
|
57
|
-
body: JSON.stringify({
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
grant_type: 'authorization_code',
|
|
59
|
+
code,
|
|
60
|
+
code_verifier: codeVerifier,
|
|
61
|
+
client_id: input.clientId,
|
|
62
|
+
redirect_uri: `${window.location.origin}${window.location.pathname}`,
|
|
63
|
+
}),
|
|
58
64
|
});
|
|
59
65
|
// Development fallback: retry without code_verifier if PKCE fails
|
|
60
66
|
if (!res.ok && !codeVerifier) {
|
|
@@ -62,7 +68,7 @@ function useOAuthCallback(input) {
|
|
|
62
68
|
method: 'POST',
|
|
63
69
|
headers: { 'Content-Type': 'application/json' },
|
|
64
70
|
credentials: 'include',
|
|
65
|
-
body: JSON.stringify({ grant_type: 'authorization_code', code }),
|
|
71
|
+
body: JSON.stringify({ grant_type: 'authorization_code', code, client_id: input.clientId, redirect_uri: `${window.location.origin}${window.location.pathname}` }),
|
|
66
72
|
});
|
|
67
73
|
}
|
|
68
74
|
if (!res.ok)
|
|
@@ -78,23 +84,11 @@ function useOAuthCallback(input) {
|
|
|
78
84
|
}
|
|
79
85
|
// 1. Save token from JWT decode FIRST — no network needed
|
|
80
86
|
saveJwt(accessToken, refreshTok);
|
|
81
|
-
|
|
82
|
-
setState({ error: null, loading: false, phase: 'done' });
|
|
83
|
-
window.location.href = input.redirectPath || '/';
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// Even if token exchange fails, saved token from JWT decode might still exist
|
|
87
|
-
if (accessToken)
|
|
88
|
-
saveJwt(accessToken, refreshTok);
|
|
89
|
-
setState({ error: 'Gagal menyelesaikan login. Silakan coba lagi.', loading: false, phase: 'error' });
|
|
90
|
-
}
|
|
91
|
-
// 3. API calls — fire-and-forget (non-blocking)
|
|
92
|
-
if (accessToken) {
|
|
93
|
-
fetch(`${apiBase}/auth/set-cookie`, {
|
|
87
|
+
await fetch(`${apiBase}/auth/set-cookie`, {
|
|
94
88
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
95
89
|
credentials: 'include',
|
|
96
90
|
body: JSON.stringify({ token: accessToken, refreshToken: refreshTok }),
|
|
97
|
-
})
|
|
91
|
+
});
|
|
98
92
|
fetch(`${apiBase}/auth/me`, {
|
|
99
93
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
100
94
|
credentials: 'include',
|
|
@@ -105,6 +99,15 @@ function useOAuthCallback(input) {
|
|
|
105
99
|
document.cookie = `sms_user_profile=${encodeURIComponent(JSON.stringify(p))}; path=/; SameSite=Lax`;
|
|
106
100
|
}
|
|
107
101
|
}).catch(() => { });
|
|
102
|
+
// 2. Redirect after Gateway cookies are persisted.
|
|
103
|
+
setState({ error: null, loading: false, phase: 'done' });
|
|
104
|
+
window.location.href = input.redirectPath || '/';
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Even if token exchange fails, saved token from JWT decode might still exist
|
|
108
|
+
if (accessToken)
|
|
109
|
+
saveJwt(accessToken, refreshTok);
|
|
110
|
+
setState({ error: 'Gagal menyelesaikan login. Silakan coba lagi.', loading: false, phase: 'error' });
|
|
108
111
|
}
|
|
109
112
|
})();
|
|
110
113
|
}, []);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { sha256 } from './sha256';
|
|
2
2
|
export { generateCodeVerifier, generateCodeChallenge, generateState, } from './pkce';
|
|
3
|
+
export { hasSsoToken, redirectToOAuthLogin } from './oauthRedirect';
|
|
4
|
+
export type { OAuthRedirectOptions } from './oauthRedirect';
|
|
3
5
|
export { SSO_STORAGE_KEYS, SSO_CHANNELS, API_HEADERS, } from './constants';
|
|
4
6
|
export { createAuthInterceptor } from './interceptor';
|
|
5
7
|
export { useOAuthCallback } from './hooks/useOAuthCallback';
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OAuthTransfer = exports.OAuthCallback = exports.useCrossAppLogout = exports.useOAuthCallback = exports.createAuthInterceptor = exports.API_HEADERS = exports.SSO_CHANNELS = exports.SSO_STORAGE_KEYS = exports.generateState = exports.generateCodeChallenge = exports.generateCodeVerifier = exports.sha256 = void 0;
|
|
3
|
+
exports.OAuthTransfer = exports.OAuthCallback = exports.useCrossAppLogout = exports.useOAuthCallback = exports.createAuthInterceptor = exports.API_HEADERS = exports.SSO_CHANNELS = exports.SSO_STORAGE_KEYS = exports.redirectToOAuthLogin = exports.hasSsoToken = exports.generateState = exports.generateCodeChallenge = exports.generateCodeVerifier = exports.sha256 = void 0;
|
|
4
4
|
var sha256_1 = require("./sha256");
|
|
5
5
|
Object.defineProperty(exports, "sha256", { enumerable: true, get: function () { return sha256_1.sha256; } });
|
|
6
6
|
var pkce_1 = require("./pkce");
|
|
7
7
|
Object.defineProperty(exports, "generateCodeVerifier", { enumerable: true, get: function () { return pkce_1.generateCodeVerifier; } });
|
|
8
8
|
Object.defineProperty(exports, "generateCodeChallenge", { enumerable: true, get: function () { return pkce_1.generateCodeChallenge; } });
|
|
9
9
|
Object.defineProperty(exports, "generateState", { enumerable: true, get: function () { return pkce_1.generateState; } });
|
|
10
|
+
var oauthRedirect_1 = require("./oauthRedirect");
|
|
11
|
+
Object.defineProperty(exports, "hasSsoToken", { enumerable: true, get: function () { return oauthRedirect_1.hasSsoToken; } });
|
|
12
|
+
Object.defineProperty(exports, "redirectToOAuthLogin", { enumerable: true, get: function () { return oauthRedirect_1.redirectToOAuthLogin; } });
|
|
10
13
|
var constants_1 = require("./constants");
|
|
11
14
|
Object.defineProperty(exports, "SSO_STORAGE_KEYS", { enumerable: true, get: function () { return constants_1.SSO_STORAGE_KEYS; } });
|
|
12
15
|
Object.defineProperty(exports, "SSO_CHANNELS", { enumerable: true, get: function () { return constants_1.SSO_CHANNELS; } });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface OAuthRedirectOptions {
|
|
2
|
+
clientId: string;
|
|
3
|
+
apiBase?: string;
|
|
4
|
+
callbackPath?: string;
|
|
5
|
+
authenticatedPath?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function hasSsoToken(): boolean;
|
|
8
|
+
export declare function redirectToOAuthLogin({ clientId, apiBase, callbackPath, authenticatedPath, }: OAuthRedirectOptions): Promise<void>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasSsoToken = hasSsoToken;
|
|
4
|
+
exports.redirectToOAuthLogin = redirectToOAuthLogin;
|
|
5
|
+
const pkce_1 = require("./pkce");
|
|
6
|
+
function trimTrailingSlash(value) {
|
|
7
|
+
return value.replace(/\/+$/, '');
|
|
8
|
+
}
|
|
9
|
+
function getCookie(name) {
|
|
10
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
11
|
+
const match = document.cookie.match(new RegExp(`(^| )${escaped}=([^;]+)`));
|
|
12
|
+
return match ? decodeURIComponent(match[2]) : '';
|
|
13
|
+
}
|
|
14
|
+
function hasSsoToken() {
|
|
15
|
+
return Boolean(getCookie('sms_ac_token') || localStorage.getItem('sms_ac_token'));
|
|
16
|
+
}
|
|
17
|
+
async function redirectToOAuthLogin({ clientId, apiBase = '/api', callbackPath = '/auth/callback', authenticatedPath = '/', }) {
|
|
18
|
+
if (hasSsoToken()) {
|
|
19
|
+
window.location.href = authenticatedPath;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const state = (0, pkce_1.generateState)();
|
|
23
|
+
const codeVerifier = (0, pkce_1.generateCodeVerifier)();
|
|
24
|
+
const codeChallenge = await (0, pkce_1.generateCodeChallenge)(codeVerifier);
|
|
25
|
+
sessionStorage.setItem(`oauth_verifier_${state}`, codeVerifier);
|
|
26
|
+
const callbackUrl = `${window.location.origin}${callbackPath}`;
|
|
27
|
+
const authorizeUrl = new URL(`${trimTrailingSlash(apiBase)}/oauth/authorize`);
|
|
28
|
+
authorizeUrl.searchParams.set('client_id', clientId);
|
|
29
|
+
authorizeUrl.searchParams.set('redirect_uri', callbackUrl);
|
|
30
|
+
authorizeUrl.searchParams.set('response_type', 'code');
|
|
31
|
+
authorizeUrl.searchParams.set('state', state);
|
|
32
|
+
authorizeUrl.searchParams.set('code_challenge', codeChallenge);
|
|
33
|
+
authorizeUrl.searchParams.set('code_challenge_method', 'S256');
|
|
34
|
+
window.location.href = authorizeUrl.toString();
|
|
35
|
+
}
|