nexus-shared 1.1.18 → 1.1.20
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/package.json +1 -1
- package/src/api-services/authentication-service.tsx +23 -0
- package/src/api-services/system-service.tsx +28 -315
- package/src/client.ts +2 -2
- package/src/components/documents/button.tsx +17 -11
- package/src/components/documents/icon-box.tsx +1 -1
- package/src/components/documents/tab-button.tsx +2 -2
- package/src/components/documents/tag.tsx +30 -0
- package/src/components/inputs/input-box.tsx +4 -2
- package/src/components/inputs/input-element.tsx +1 -1
- package/src/components/inputs/input-form.tsx +126 -14
- package/src/components/layouts/global-dialogbox.tsx +5 -9
- package/src/components/layouts/global-layout.tsx +3 -0
- package/src/components/layouts/layout-helpers.tsx +1 -4
- package/src/components/layouts/panels/user-panel.tsx +112 -0
- package/src/components/layouts/utility-menu.tsx +9 -29
- package/src/components/panels/theme-panel.tsx +2 -2
- package/src/helpers/browser-helpers.tsx +88 -3
- package/src/helpers/input-helpers.tsx +34 -4
- package/src/helpers/validation-helpers.tsx +302 -0
- package/src/index.ts +2 -18
- package/src/interface.ts +5 -1
- package/src/interfaces/auth-token-interfaces.tsx +6 -0
- package/src/interfaces/browser-interfaces.tsx +13 -0
- package/src/interfaces/button-interfaces.tsx +2 -2
- package/src/interfaces/http-interfaces.tsx +86 -8
- package/src/interfaces/icon-interfaces.tsx +3 -0
- package/src/interfaces/input-interfaces.tsx +61 -11
- package/src/interfaces/menu-interfaces.tsx +13 -0
- package/src/interfaces/message-interfaces.tsx +32 -0
- package/src/interfaces/storage-interfaces.tsx +2 -0
- package/src/interfaces/theme-interfaces.tsx +43 -129
- package/src/interfaces/type-interfaces.tsx +8 -2
- package/src/interfaces/user-interfaces.tsx +47 -0
- package/src/nexus.environments.tsx +41 -24
- package/src/proxy-api/proxy-backend.tsx +60 -0
- package/src/proxy-api/proxy-constants.tsx +28 -0
- package/src/proxy-api/proxy-helpers.tsx +91 -0
- package/src/proxy-api-client.tsx +1 -0
- package/src/proxy-api-server.tsx +2 -0
- package/src/services/http-client-services.tsx +26 -11
- package/src/services/http-services.tsx +42 -27
- package/src/services/loader-service.tsx +34 -17
- package/src/services/localstorage-service.tsx +81 -5
- package/src/services/message-services.tsx +383 -0
- package/src/services/theme-service.tsx +30 -16
- package/src/services/user-services.tsx +10 -0
- package/src/sso-config/auth-token-validation.ts +16 -0
- package/src/sso-config/callback-route.tsx +35 -0
- package/src/sso-config/cookie-encryption.ts +51 -0
- package/src/sso-config/cookie-helpers.tsx +102 -0
- package/src/sso-config/forgot-password-route.tsx +36 -0
- package/src/sso-config/oauth-callback-state.ts +61 -0
- package/src/sso-config/pkce-helpers.ts +9 -0
- package/src/sso-config/provider-complete-route.tsx +18 -0
- package/src/sso-config/redirect-context-actions.tsx +45 -0
- package/src/sso-config/redirect-context-helpers.tsx +159 -0
- package/src/sso-config/redirect-context-persist.tsx +18 -0
- package/src/sso-config/redirect-context-route.tsx +45 -0
- package/src/sso-config/refresh-route.tsx +23 -0
- package/src/sso-config/sign-in-route.tsx +74 -0
- package/src/sso-config/sign-out-route.tsx +57 -0
- package/src/sso-config/sign-up-route.tsx +57 -0
- package/src/sso-config/sso-backend-flow.ts +38 -0
- package/src/sso-config/sso-complete-route.tsx +50 -0
- package/src/sso-config/sso-config.ts +59 -0
- package/src/sso-config/sso-interfaces.tsx +99 -0
- package/src/sso-config/sso-response-helpers.tsx +20 -0
- package/src/sso-server.tsx +21 -1
- package/src/styles/nexus.dialog.css +3 -0
- package/src/styles/nexus.icon.css +1 -0
- package/src/styles/nexus.logic.css +34 -5
- package/src/interfaces/sso-interfaces.tsx +0 -52
- package/src/load-env.ts +0 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import { HttpPost } from "../services/http-services";
|
|
3
|
+
import { AUTH_COOKIES, ResolvePostLoginRedirectUrl, SetSsoSessionCookie } from "./cookie-helpers";
|
|
4
|
+
import { DecodeRedirectContext } from "./redirect-context-helpers";
|
|
5
|
+
import { GetClientConfiguration } from "./sso-backend-flow";
|
|
6
|
+
import { SSO_CONFIG } from "./sso-config";
|
|
7
|
+
import { ISignUpRequest } from "./sso-interfaces";
|
|
8
|
+
import { ParseWrappedResult } from "./sso-response-helpers";
|
|
9
|
+
|
|
10
|
+
const mapGender = (gender?: string | null) => {
|
|
11
|
+
const normalized = gender?.trim().toLowerCase();
|
|
12
|
+
if (normalized === "male") return 0;
|
|
13
|
+
if (normalized === "female") return 1;
|
|
14
|
+
return 2;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** POST — register a new account (identity provider app). */
|
|
18
|
+
export async function SignUpPostRoute(req: NextRequest) {
|
|
19
|
+
const body = (await req.json()) as ISignUpRequest & { confirmPassword?: string };
|
|
20
|
+
|
|
21
|
+
if (!body.fullName?.trim() || !body.username?.trim() || !body.email?.trim() || !body.password || !body.confirmPassword) {
|
|
22
|
+
return NextResponse.json({ error: "All required fields must be provided." }, { status: 400 });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (body.password !== body.confirmPassword) {
|
|
26
|
+
return NextResponse.json({ error: "Passwords do not match." }, { status: 400 });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const signUpRes = await HttpPost(SSO_CONFIG.BACKEND_ENDPOINTS.SIGN_UP, {
|
|
30
|
+
fullname: body.fullName.trim(),
|
|
31
|
+
username: body.username.trim(),
|
|
32
|
+
password: body.password,
|
|
33
|
+
confirmPassword: body.confirmPassword,
|
|
34
|
+
genderType: mapGender(body.gender),
|
|
35
|
+
emailAddress: body.email.trim(),
|
|
36
|
+
contactNumber: null,
|
|
37
|
+
clientSystemName: SSO_CONFIG.BACKEND_CONFIG.CLIENT_SYSTEM_NAME,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const signUpResult = ParseWrappedResult<{ ssoSession: string }>(signUpRes);
|
|
41
|
+
if (!signUpRes.isSuccess || !signUpResult?.ssoSession) {
|
|
42
|
+
return NextResponse.json(signUpRes, { status: signUpRes.code ?? 400 });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const ssoConfiguration = await GetClientConfiguration();
|
|
46
|
+
const redirectContext = DecodeRedirectContext(req.cookies.get(AUTH_COOKIES.redirectContext)?.value);
|
|
47
|
+
|
|
48
|
+
const response = NextResponse.json({
|
|
49
|
+
...signUpRes,
|
|
50
|
+
result: {
|
|
51
|
+
...signUpResult,
|
|
52
|
+
redirectUrl: ResolvePostLoginRedirectUrl(!!redirectContext?.redirectUri),
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
SetSsoSessionCookie(response, signUpResult.ssoSession, ssoConfiguration.ssoSessionLifetime);
|
|
56
|
+
return response;
|
|
57
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { NEXUS_CONFIG } from "../nexus.environments";
|
|
2
|
+
import { HttpGet, HttpPost } from "../services/http-services";
|
|
3
|
+
import { SSO_CONFIG } from "./sso-config";
|
|
4
|
+
import { IClientApplication, PKCE_METHOD_S256, SSOAuthResponse, SsoExchangeInput, TokenExchangeInput } from "./sso-interfaces";
|
|
5
|
+
import { ParseSsoCodeResponse, ParseTokenResponse } from "./sso-response-helpers";
|
|
6
|
+
|
|
7
|
+
/** Server-only: request an authorization code using client policy + PKCE. */
|
|
8
|
+
export async function RequestAuthorizationCode(input: SsoExchangeInput): Promise<string | null> {
|
|
9
|
+
const ssoRes = await HttpPost(SSO_CONFIG.BACKEND_ENDPOINTS.SSO, {
|
|
10
|
+
ssoSession: input.ssoSession,
|
|
11
|
+
redirectUri: input.redirectUri,
|
|
12
|
+
state: input.state,
|
|
13
|
+
returnPath: input.returnPath,
|
|
14
|
+
codeChallenge: input.pkce.challenge,
|
|
15
|
+
codeChallengeMethod: input.pkce.method ?? PKCE_METHOD_S256,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return ParseSsoCodeResponse(ssoRes);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Server-only: exchange authorization code for tokens. */
|
|
22
|
+
export async function ExchangeAuthorizationCode(input: TokenExchangeInput): Promise<SSOAuthResponse | null> {
|
|
23
|
+
const tokenRes = await HttpPost(SSO_CONFIG.BACKEND_ENDPOINTS.TOKEN, {
|
|
24
|
+
code: input.code,
|
|
25
|
+
redirectUri: input.redirectUri,
|
|
26
|
+
clientSystemName: SSO_CONFIG.BACKEND_CONFIG.CLIENT_SYSTEM_NAME,
|
|
27
|
+
codeVerifier: input.codeVerifier,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return ParseTokenResponse(tokenRes);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Server-only: get client configuration from the backend. */
|
|
34
|
+
export async function GetClientConfiguration(): Promise<IClientApplication> {
|
|
35
|
+
const clientConfigRes = await HttpGet(SSO_CONFIG.BACKEND_ENDPOINTS.CLIENT_CONFIG, null, NEXUS_CONFIG.DEFAULT_REVALIDATE_TIME_ONE_DAY);
|
|
36
|
+
if (!clientConfigRes.isSuccess) throw new Error("Failed to get client configuration");
|
|
37
|
+
return clientConfigRes.result;
|
|
38
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import { AUTH_COOKIES, GetDecryptedRequestCookie } from "./cookie-helpers";
|
|
3
|
+
import { EncodeOAuthCallbackState } from "./oauth-callback-state";
|
|
4
|
+
import { ClearRedirectContextCookie, DecodeRedirectContext } from "./redirect-context-helpers";
|
|
5
|
+
import { RequestAuthorizationCode } from "./sso-backend-flow";
|
|
6
|
+
import { BuildAuthenticationSignInUrl, SSO_CONFIG } from "./sso-config";
|
|
7
|
+
import { PKCE_METHOD_S256, PkcePair } from "./sso-interfaces";
|
|
8
|
+
|
|
9
|
+
function buildSignInRedirect(redirectContext: ReturnType<typeof DecodeRedirectContext>) {
|
|
10
|
+
return new URL(BuildAuthenticationSignInUrl(redirectContext?.returnPath));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Completes SSO after credentials sign-in: exchange session for code and redirect to the client callback. */
|
|
14
|
+
export async function SsoCompleteRoute(req: NextRequest) {
|
|
15
|
+
const ssoSession = GetDecryptedRequestCookie(req, AUTH_COOKIES.ssoSession);
|
|
16
|
+
const redirectContext = DecodeRedirectContext(req.cookies.get(AUTH_COOKIES.redirectContext)?.value);
|
|
17
|
+
|
|
18
|
+
if (!ssoSession) {
|
|
19
|
+
return NextResponse.redirect(buildSignInRedirect(redirectContext));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!redirectContext?.redirectUri) {
|
|
23
|
+
return NextResponse.redirect(new URL(SSO_CONFIG.FRONTEND_ENDPOINTS.SIGN_IN, req.url));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const pkce: PkcePair = {
|
|
27
|
+
verifier: redirectContext.pkceVerifier,
|
|
28
|
+
challenge: redirectContext.codeChallenge,
|
|
29
|
+
method: (redirectContext.codeChallengeMethod as PkcePair["method"]) ?? PKCE_METHOD_S256,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const code = await RequestAuthorizationCode({
|
|
34
|
+
ssoSession,
|
|
35
|
+
redirectUri: redirectContext.redirectUri,
|
|
36
|
+
state: redirectContext.state,
|
|
37
|
+
returnPath: redirectContext.returnPath,
|
|
38
|
+
pkce,
|
|
39
|
+
});
|
|
40
|
+
if (!code) return NextResponse.redirect(buildSignInRedirect(redirectContext));
|
|
41
|
+
|
|
42
|
+
const callbackState = EncodeOAuthCallbackState(redirectContext.state, redirectContext.returnPath, pkce.verifier);
|
|
43
|
+
const location = `${redirectContext.redirectUri}?code=${encodeURIComponent(code)}&state=${encodeURIComponent(callbackState)}`;
|
|
44
|
+
const response = NextResponse.redirect(location);
|
|
45
|
+
ClearRedirectContextCookie(response);
|
|
46
|
+
return response;
|
|
47
|
+
} catch {
|
|
48
|
+
return NextResponse.redirect(buildSignInRedirect(redirectContext));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { APIS, URLS } from "nexus-shared";
|
|
2
|
+
|
|
3
|
+
const _callbackPath = `${URLS.CURRENT}/api/auth/callback`;
|
|
4
|
+
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
const processEnv = process.env;
|
|
7
|
+
|
|
8
|
+
export const SSO_CONFIG = {
|
|
9
|
+
COOKIE_CONFIG: {
|
|
10
|
+
COOKIE_SECRET: processEnv.SSO_COOKIE_SECRET as string,
|
|
11
|
+
},
|
|
12
|
+
BACKEND_ENDPOINTS: {
|
|
13
|
+
SIGN_IN: `${APIS.AUTHENTICATION}/Authentication/SignIn`,
|
|
14
|
+
SIGN_UP: `${APIS.AUTHENTICATION}/Authentication/SignUp`,
|
|
15
|
+
SSO: `${APIS.AUTHENTICATION}/Authentication/SSO`,
|
|
16
|
+
TOKEN: `${APIS.AUTHENTICATION}/Authentication/Token`,
|
|
17
|
+
REFRESH: `${APIS.AUTHENTICATION}/Authentication/Refresh`,
|
|
18
|
+
SIGN_OUT: `${APIS.AUTHENTICATION}/Authentication/SignOut`,
|
|
19
|
+
PROVIDERS: `${APIS.AUTHENTICATION}/Authentication/Providers`,
|
|
20
|
+
CLIENT_CONFIG: `${APIS.AUTHENTICATION}/Authentication/ClientConfig/${processEnv.AUTH_CLIENT_SYSTEM_NAME}`,
|
|
21
|
+
FORGOT_PASSWORD: `${APIS.AUTHENTICATION}/Authentication/ForgotPassword`,
|
|
22
|
+
RESET_PASSWORD: `${APIS.AUTHENTICATION}/Authentication/ResetPassword`,
|
|
23
|
+
/** Used by VerifyAccessToken — returns 200 for a valid Bearer token, 401 otherwise. */
|
|
24
|
+
VERIFY: `${APIS.AUTHENTICATION}/Authentication/Verify`,
|
|
25
|
+
PROVIDER_CHALLENGE: (provider: string, returnUrl: string, clientSystemName: string) => `${APIS.AUTHENTICATION}/Provider/${provider}/Challenge?returnUrl=${encodeURIComponent(returnUrl)}&clientSystemName=${encodeURIComponent(clientSystemName)}`,
|
|
26
|
+
},
|
|
27
|
+
BACKEND_CONFIG: {
|
|
28
|
+
/** Matches AuthenticationOptions.DefaultClientSystemName (NEXUS_WEB_APPLICATION_API). */
|
|
29
|
+
CLIENT_SYSTEM_NAME: processEnv.AUTH_CLIENT_SYSTEM_NAME as string,
|
|
30
|
+
/** How long redirect_uri/state survive in a secure httpOnly cookie on the auth app (seconds). */
|
|
31
|
+
REDIRECT_CONTEXT_MAX_AGE: processEnv.REDIRECT_CONTEXT_MAX_AGE as string,
|
|
32
|
+
},
|
|
33
|
+
FRONTEND_ENDPOINTS: {
|
|
34
|
+
CALLBACK: _callbackPath,
|
|
35
|
+
SIGN_IN: `${URLS.CURRENT}/api/auth/sign-in`,
|
|
36
|
+
SIGN_UP: `${URLS.CURRENT}/api/auth/sign-up`,
|
|
37
|
+
SIGN_OUT: `${URLS.CURRENT}/api/auth/sign-out`,
|
|
38
|
+
REFRESH: `${URLS.CURRENT}/api/auth/refresh`,
|
|
39
|
+
SSO_COMPLETE: `${URLS.CURRENT}/api/auth/sso-complete`,
|
|
40
|
+
PROVIDER_COMPLETE: `${URLS.CURRENT}/api/auth/provider-complete`,
|
|
41
|
+
FORGOT_PASSWORD: `${URLS.CURRENT}/api/auth/forgot-password`,
|
|
42
|
+
RESET_PASSWORD: `${URLS.CURRENT}/api/auth/reset-password`,
|
|
43
|
+
},
|
|
44
|
+
} as const;
|
|
45
|
+
|
|
46
|
+
/** Client-app entry URL for centralized sign-in (includes redirect_uri + optional return path). */
|
|
47
|
+
export function BuildAuthenticationSignInUrl(returnPath?: string) {
|
|
48
|
+
const entryUrl = new URL(`${URLS.AUTHENTICATION}/api/auth/redirect-context`);
|
|
49
|
+
entryUrl.searchParams.set("redirect_uri", SSO_CONFIG.FRONTEND_ENDPOINTS.CALLBACK);
|
|
50
|
+
if (returnPath) entryUrl.searchParams.set("state", returnPath);
|
|
51
|
+
return entryUrl.toString();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Sign-out URL that returns the user to a page on this app after cookies are cleared. */
|
|
55
|
+
export function BuildSignOutUrl(returnPath?: string) {
|
|
56
|
+
const signOutUrl = new URL(SSO_CONFIG.FRONTEND_ENDPOINTS.SIGN_OUT);
|
|
57
|
+
if (returnPath) signOutUrl.searchParams.set("returnUrl", returnPath);
|
|
58
|
+
return signOutUrl.toString();
|
|
59
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { UN } from "../interfaces/type-interfaces";
|
|
2
|
+
|
|
3
|
+
export const PKCE_METHOD_S256 = "S256";
|
|
4
|
+
|
|
5
|
+
export interface SSOAuthResponse {
|
|
6
|
+
accessToken: string;
|
|
7
|
+
refreshToken: string;
|
|
8
|
+
expiresTokenIn: number;
|
|
9
|
+
expiresRefreshTokenIn: number;
|
|
10
|
+
returnPath?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CookieInfo {
|
|
14
|
+
ssoSession?: string;
|
|
15
|
+
accessToken?: string | UN;
|
|
16
|
+
refreshToken?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface IRedirectContext {
|
|
20
|
+
redirectUri: string;
|
|
21
|
+
/** OAuth CSRF nonce sent to the client callback. */
|
|
22
|
+
state: string;
|
|
23
|
+
/** Relative path to return to after sign-in completes. */
|
|
24
|
+
returnPath: string;
|
|
25
|
+
/** PKCE code challenge (stored server-side until SSO). */
|
|
26
|
+
codeChallenge: string;
|
|
27
|
+
codeChallengeMethod: string;
|
|
28
|
+
/** PKCE verifier (server-side only; also embedded in signed callback state). */
|
|
29
|
+
pkceVerifier: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ISignInParams {
|
|
33
|
+
redirect_uri: string | UN;
|
|
34
|
+
state: string | UN;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ISsoSessionResponse {
|
|
38
|
+
code: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ILoginRequest {
|
|
42
|
+
username: string;
|
|
43
|
+
password: string;
|
|
44
|
+
rememberMe: boolean;
|
|
45
|
+
clientSystemName: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ILoginResponse {
|
|
49
|
+
ssoSession: string;
|
|
50
|
+
displayName: string;
|
|
51
|
+
role: string;
|
|
52
|
+
userId: number;
|
|
53
|
+
redirectUrl?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ISignUpRequest {
|
|
57
|
+
fullName: string;
|
|
58
|
+
gender?: string | UN;
|
|
59
|
+
username: string;
|
|
60
|
+
email: string;
|
|
61
|
+
password: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface IDemoUserInfo {
|
|
65
|
+
id: number;
|
|
66
|
+
username: string;
|
|
67
|
+
email: string;
|
|
68
|
+
displayName: string;
|
|
69
|
+
role: string;
|
|
70
|
+
passwordHint: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type SsoExchangeInput = {
|
|
74
|
+
ssoSession: string;
|
|
75
|
+
redirectUri: string;
|
|
76
|
+
state?: string;
|
|
77
|
+
returnPath?: string;
|
|
78
|
+
pkce: PkcePair;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export type TokenExchangeInput = {
|
|
82
|
+
code: string;
|
|
83
|
+
redirectUri: string;
|
|
84
|
+
codeVerifier: string;
|
|
85
|
+
};
|
|
86
|
+
export type PkcePair = {
|
|
87
|
+
verifier: string;
|
|
88
|
+
challenge: string;
|
|
89
|
+
method: typeof PKCE_METHOD_S256;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export interface IClientApplication {
|
|
93
|
+
requirePkce: boolean;
|
|
94
|
+
accessTokenLifetime: number;
|
|
95
|
+
refreshTokenLifetime: number;
|
|
96
|
+
authorizationCodeLifetime: number;
|
|
97
|
+
ssoSessionLifetime: number;
|
|
98
|
+
allowOfflineAccess: boolean;
|
|
99
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IErrorRespose, ISuccessResponse } from "../interfaces/http-interfaces";
|
|
2
|
+
import { ISsoSessionResponse, SSOAuthResponse } from "./sso-interfaces";
|
|
3
|
+
|
|
4
|
+
type ApiResponse = ISuccessResponse | IErrorRespose;
|
|
5
|
+
|
|
6
|
+
export function ParseWrappedResult<T>(response: ApiResponse): T | null {
|
|
7
|
+
if (!response.isSuccess) return null;
|
|
8
|
+
return (response.result ?? null) as T | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function ParseSsoCodeResponse(response: ApiResponse): string | null {
|
|
12
|
+
const result = ParseWrappedResult<ISsoSessionResponse | { code?: string }>(response);
|
|
13
|
+
if (!result) return null;
|
|
14
|
+
if ("code" in result && result.code) return result.code;
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function ParseTokenResponse(response: ApiResponse): SSOAuthResponse | null {
|
|
19
|
+
return ParseWrappedResult<SSOAuthResponse>(response);
|
|
20
|
+
}
|
package/src/sso-server.tsx
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from "./sso-config/oauth-callback-state";
|
|
2
|
+
export * from "./sso-config/pkce-helpers";
|
|
3
|
+
export * from "./sso-config/sso-backend-flow";
|
|
4
|
+
export * from "./sso-config/auth-token-validation";
|
|
5
|
+
export * from "./sso-config/callback-route";
|
|
6
|
+
export * from "./sso-config/cookie-helpers";
|
|
7
|
+
export * from "./sso-config/redirect-context-actions";
|
|
8
|
+
export * from "./sso-config/redirect-context-helpers";
|
|
9
|
+
export * from "./sso-config/redirect-context-route";
|
|
10
|
+
export * from "./sso-config/redirect-context-persist";
|
|
11
|
+
export * from "./sso-config/refresh-route";
|
|
12
|
+
export * from "./sso-config/sign-in-route";
|
|
13
|
+
export * from "./sso-config/sign-out-route";
|
|
14
|
+
export * from "./sso-config/sign-up-route";
|
|
15
|
+
export * from "./sso-config/sso-response-helpers";
|
|
16
|
+
export * from "./sso-config/forgot-password-route";
|
|
17
|
+
export * from "./sso-config/provider-complete-route";
|
|
18
|
+
export * from "./sso-config/sso-complete-route";
|
|
19
|
+
export * from "./sso-config/sso-config";
|
|
20
|
+
export * from "./sso-config/sso-interfaces";
|
|
21
|
+
export * from "./sso-config/sso-response-helpers";
|
|
@@ -1,18 +1,47 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--ACTIVE_BACKGROUND_COLOR: var(--B1);
|
|
3
|
+
--ACTIVE_BORDER_COLOR: var(--B20);
|
|
4
|
+
--ACTIVE_TEXT_COLOR: var(--T1);
|
|
5
|
+
}
|
|
6
|
+
.item .ho1 {
|
|
7
|
+
opacity: 0;
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
.ho1:hover {
|
|
2
11
|
opacity: 1;
|
|
3
12
|
}
|
|
4
|
-
.btn.active
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
.btn.active {
|
|
13
|
+
.btn.active,
|
|
14
|
+
.btn.left-active {
|
|
8
15
|
background-color: var(--ACTIVE_BACKGROUND_COLOR) !important;
|
|
9
16
|
pointer-events: none;
|
|
17
|
+
border-radius: 0 !important;
|
|
18
|
+
opacity: 1 !important;
|
|
10
19
|
}
|
|
11
|
-
.btn.active::after
|
|
20
|
+
.btn.active::after,
|
|
21
|
+
.btn.left-active::after {
|
|
12
22
|
content: " ";
|
|
13
23
|
position: absolute;
|
|
14
24
|
width: 100%;
|
|
15
25
|
height: var(--BRD2);
|
|
16
26
|
bottom: 0;
|
|
27
|
+
left: 0;
|
|
17
28
|
background-color: var(--ACTIVE_BORDER_COLOR);
|
|
18
29
|
}
|
|
30
|
+
|
|
31
|
+
.btn.left-active::after {
|
|
32
|
+
width: calc(var(--BRD2) * 3) !important;
|
|
33
|
+
height: 100% !important;
|
|
34
|
+
bottom: unset;
|
|
35
|
+
top: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.btn.active,
|
|
39
|
+
.btn.left-active,
|
|
40
|
+
.btn.active span,
|
|
41
|
+
.btn.active .icon,
|
|
42
|
+
.btn.left-active .icon,
|
|
43
|
+
.btn.left-active span {
|
|
44
|
+
color: var(--ACTIVE_TEXT_COLOR) !important;
|
|
45
|
+
font-weight: 600 !important;
|
|
46
|
+
opacity: 1 !important;
|
|
47
|
+
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { UN } from "nexus-shared";
|
|
2
|
-
export interface SSOAuthResponse {
|
|
3
|
-
accessToken: string;
|
|
4
|
-
refreshToken: string;
|
|
5
|
-
expiresTokenIn: number;
|
|
6
|
-
expiresRefreshTokenIn: number;
|
|
7
|
-
returnPath?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface CookieInfo {
|
|
11
|
-
ssoSession: string;
|
|
12
|
-
accessToken: string | UN;
|
|
13
|
-
refreshToken: string | UN;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface IRedirectContext {
|
|
17
|
-
redirectUri: string;
|
|
18
|
-
/** OAuth CSRF nonce sent to the client callback. */
|
|
19
|
-
state: string;
|
|
20
|
-
/** Relative path to return to after sign-in completes. */
|
|
21
|
-
returnPath: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface ISignInParams {
|
|
25
|
-
redirect_uri: string | UN;
|
|
26
|
-
state: string | UN;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface ISsoSessionResponse {
|
|
30
|
-
code: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface ILoginRequest {
|
|
34
|
-
username: string;
|
|
35
|
-
password: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ILoginResponse {
|
|
39
|
-
ssoSession: string;
|
|
40
|
-
displayName: string;
|
|
41
|
-
role: string;
|
|
42
|
-
userId: number;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface IDemoUserInfo {
|
|
46
|
-
id: number;
|
|
47
|
-
username: string;
|
|
48
|
-
email: string;
|
|
49
|
-
displayName: string;
|
|
50
|
-
role: string;
|
|
51
|
-
passwordHint: string;
|
|
52
|
-
}
|
package/src/load-env.ts
DELETED