@multiplatform.one/keycloak 0.7.15 → 0.7.16
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 +26 -26
- package/routes/index.d.ts +22 -0
- package/routes/index.js +22 -0
- package/src/Authenticated.tsx +27 -17
- package/src/authConfig.ts +3 -9
- package/src/hooks/index.ts +0 -3
- package/src/hooks/useTokensFromQuery/index.ts +1 -0
- package/src/hooks/useTokensFromState.ts +1 -1
- package/src/index.ts +3 -0
- package/src/{@types/coreJsPure.d.ts → keycloak/context.ts} +6 -11
- package/{lib/@types/expoKeycloakAuth.d.d.mts → src/keycloak/index.ts} +4 -7
- package/src/keycloak/keycloak.native.ts +148 -0
- package/src/keycloak/keycloak.ts +175 -0
- package/src/provider/AfterAuth.tsx +63 -0
- package/src/provider/{keycloakProvider.native.tsx → AuthProvider/AuthProvider.native.tsx} +8 -16
- package/src/provider/{keycloakProvider.tsx → AuthProvider/AuthProvider.tsx} +81 -94
- package/{lib/@types/expoKeycloakAuth.d.d.ts → src/provider/AuthProvider/index.ts} +4 -7
- package/src/provider/KeycloakProvider.tsx +53 -0
- package/src/{hooks/useCurrentRouteName/index.native.ts → provider/index.ts} +6 -11
- package/src/routes.ts +163 -0
- package/src/session/index.ts +22 -0
- package/src/session/session.native.ts +31 -0
- package/src/session/session.ts +68 -0
- package/src/{state/index.ts → state.ts} +5 -4
- package/src/{util.ts → token.ts} +25 -11
- package/src/types.ts +4 -1
- package/lib/@types/coreJsPure.d.d.mts +0 -2
- package/lib/@types/coreJsPure.d.d.ts +0 -2
- package/lib/@types/coreJsPure.d.js +0 -1
- package/lib/@types/coreJsPure.d.mjs +0 -0
- package/lib/@types/expoKeycloakAuth.d.js +0 -1
- package/lib/@types/expoKeycloakAuth.d.mjs +0 -0
- package/lib/Authenticated.d.mts +0 -33
- package/lib/Authenticated.d.ts +0 -33
- package/lib/Authenticated.js +0 -19
- package/lib/Authenticated.mjs +0 -20
- package/lib/authConfig.d.mts +0 -14
- package/lib/authConfig.d.ts +0 -14
- package/lib/authConfig.js +0 -8
- package/lib/authConfig.mjs +0 -9
- package/lib/chunk-2GUOEPFY.mjs +0 -0
- package/lib/chunk-3ZPHNEJL.js +0 -11
- package/lib/chunk-64PPU7Q3.mjs +0 -13
- package/lib/chunk-6NDWOV55.js +0 -1
- package/lib/chunk-7MTPH6XK.mjs +0 -26
- package/lib/chunk-A7UBOIAL.js +0 -13
- package/lib/chunk-AD6VPMID.mjs +0 -20
- package/lib/chunk-AUUZ6BI7.js +0 -78
- package/lib/chunk-AYKQVWMR.mjs +0 -0
- package/lib/chunk-BVB33X7V.mjs +0 -265
- package/lib/chunk-C2FNSVJO.js +0 -17
- package/lib/chunk-J4CCMILN.mjs +0 -41
- package/lib/chunk-K33RKJZX.js +0 -443
- package/lib/chunk-KLLABHIC.js +0 -13
- package/lib/chunk-L5HMOY4M.mjs +0 -18
- package/lib/chunk-MZ6E62HK.js +0 -33
- package/lib/chunk-NWRANDZ6.js +0 -98
- package/lib/chunk-NXTVYIBR.mjs +0 -11
- package/lib/chunk-OYWAYMFN.js +0 -17
- package/lib/chunk-RPUOO7AV.mjs +0 -10
- package/lib/chunk-RYM7KERK.mjs +0 -52
- package/lib/chunk-UBVYEZI3.js +0 -1
- package/lib/chunk-UHTKOFS6.mjs +0 -84
- package/lib/chunk-UL6L5ONI.js +0 -460
- package/lib/chunk-UOKDJT5L.mjs +0 -16
- package/lib/chunk-W5DJLFTQ.js +0 -56
- package/lib/chunk-WT5W6BSZ.js +0 -161
- package/lib/chunk-XEO3YXBM.js +0 -22
- package/lib/chunk-XO4W2SMN.mjs +0 -50
- package/lib/chunk-XVPWAAZ4.mjs +0 -76
- package/lib/chunk-Y4XMF3R6.mjs +0 -13
- package/lib/chunk-YGNNHTFE.js +0 -12
- package/lib/hooks/index.d.mts +0 -9
- package/lib/hooks/index.d.ts +0 -9
- package/lib/hooks/index.js +0 -23
- package/lib/hooks/index.mjs +0 -34
- package/lib/hooks/useAuthConfig.d.mts +0 -6
- package/lib/hooks/useAuthConfig.d.ts +0 -6
- package/lib/hooks/useAuthConfig.js +0 -8
- package/lib/hooks/useAuthConfig.mjs +0 -8
- package/lib/hooks/useCurrentRouteName/index.d.mts +0 -3
- package/lib/hooks/useCurrentRouteName/index.d.ts +0 -3
- package/lib/hooks/useCurrentRouteName/index.js +0 -7
- package/lib/hooks/useCurrentRouteName/index.mjs +0 -7
- package/lib/hooks/useCurrentRouteName/index.native.d.mts +0 -3
- package/lib/hooks/useCurrentRouteName/index.native.d.ts +0 -3
- package/lib/hooks/useCurrentRouteName/index.native.js +0 -14
- package/lib/hooks/useCurrentRouteName/index.native.mjs +0 -14
- package/lib/hooks/useKeycloak/index.d.mts +0 -46
- package/lib/hooks/useKeycloak/index.d.ts +0 -46
- package/lib/hooks/useKeycloak/index.js +0 -11
- package/lib/hooks/useKeycloak/index.mjs +0 -12
- package/lib/hooks/useKeycloak/useKeycloak.d.mts +0 -2
- package/lib/hooks/useKeycloak/useKeycloak.d.ts +0 -2
- package/lib/hooks/useKeycloak/useKeycloak.js +0 -10
- package/lib/hooks/useKeycloak/useKeycloak.mjs +0 -11
- package/lib/hooks/useKeycloak/useKeycloak.native.d.mts +0 -20
- package/lib/hooks/useKeycloak/useKeycloak.native.d.ts +0 -20
- package/lib/hooks/useKeycloak/useKeycloak.native.js +0 -80
- package/lib/hooks/useKeycloak/useKeycloak.native.mjs +0 -69
- package/lib/hooks/useLogin.d.mts +0 -3
- package/lib/hooks/useLogin.d.ts +0 -3
- package/lib/hooks/useLogin.js +0 -11
- package/lib/hooks/useLogin.mjs +0 -11
- package/lib/hooks/useTokensFromQuery/index.d.mts +0 -3
- package/lib/hooks/useTokensFromQuery/index.d.ts +0 -3
- package/lib/hooks/useTokensFromQuery/index.js +0 -7
- package/lib/hooks/useTokensFromQuery/index.mjs +0 -7
- package/lib/hooks/useTokensFromQuery/index.native.d.mts +0 -3
- package/lib/hooks/useTokensFromQuery/index.native.d.ts +0 -3
- package/lib/hooks/useTokensFromQuery/index.native.js +0 -10
- package/lib/hooks/useTokensFromQuery/index.native.mjs +0 -7
- package/lib/hooks/useTokensFromState.d.mts +0 -3
- package/lib/hooks/useTokensFromState.d.ts +0 -3
- package/lib/hooks/useTokensFromState.js +0 -9
- package/lib/hooks/useTokensFromState.mjs +0 -9
- package/lib/index.d.mts +0 -13
- package/lib/index.d.ts +0 -13
- package/lib/index.js +0 -34
- package/lib/index.mjs +0 -56
- package/lib/provider/afterAuth.d.mts +0 -29
- package/lib/provider/afterAuth.d.ts +0 -29
- package/lib/provider/afterAuth.js +0 -18
- package/lib/provider/afterAuth.mjs +0 -18
- package/lib/provider/index.d.mts +0 -39
- package/lib/provider/index.d.ts +0 -39
- package/lib/provider/index.js +0 -22
- package/lib/provider/index.mjs +0 -25
- package/lib/provider/keycloakProvider.d.mts +0 -42
- package/lib/provider/keycloakProvider.d.ts +0 -42
- package/lib/provider/keycloakProvider.js +0 -20
- package/lib/provider/keycloakProvider.mjs +0 -21
- package/lib/provider/keycloakProvider.native.d.mts +0 -29
- package/lib/provider/keycloakProvider.native.d.ts +0 -29
- package/lib/provider/keycloakProvider.native.js +0 -87
- package/lib/provider/keycloakProvider.native.mjs +0 -30
- package/lib/state/index.d.mts +0 -11
- package/lib/state/index.d.ts +0 -11
- package/lib/state/index.js +0 -7
- package/lib/state/index.mjs +0 -7
- package/lib/types.d.mts +0 -17
- package/lib/types.d.ts +0 -17
- package/lib/types.js +0 -8
- package/lib/types.mjs +0 -7
- package/lib/util.d.mts +0 -4
- package/lib/util.d.ts +0 -4
- package/lib/util.js +0 -8
- package/lib/util.mjs +0 -9
- package/src/hooks/useCurrentRouteName/index.ts +0 -34
- package/src/hooks/useKeycloak/index.ts +0 -47
- package/src/hooks/useKeycloak/useKeycloak.native.ts +0 -95
- package/src/hooks/useKeycloak/useKeycloak.ts +0 -106
- package/src/hooks/useLogin.ts +0 -47
- package/src/provider/afterAuth.tsx +0 -65
- package/src/provider/index.tsx +0 -117
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/provider/AfterAuth.tsx
|
|
3
|
+
* Project: @multiplatform.one/keycloak
|
|
4
|
+
* File Created: 10-01-2024 12:41:33
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import React, { useEffect } from 'react';
|
|
23
|
+
import type { PropsWithChildren } from 'react';
|
|
24
|
+
import { useAuthConfig } from '../hooks';
|
|
25
|
+
import { useAuthState, persist } from '../state';
|
|
26
|
+
import { useKeycloak } from '../keycloak';
|
|
27
|
+
|
|
28
|
+
export interface AfterAuthProps extends PropsWithChildren {}
|
|
29
|
+
|
|
30
|
+
const logger = console;
|
|
31
|
+
|
|
32
|
+
export function AfterAuth({ children }: AfterAuthProps) {
|
|
33
|
+
const authConfig = useAuthConfig();
|
|
34
|
+
const authState = useAuthState();
|
|
35
|
+
const keycloak = useKeycloak();
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!persist || !keycloak?.authenticated) return;
|
|
39
|
+
if (keycloak.token) {
|
|
40
|
+
authState.setToken(keycloak.token);
|
|
41
|
+
if (keycloak.idToken) authState.setIdToken(keycloak.idToken);
|
|
42
|
+
if (keycloak.refreshToken) authState.setRefreshToken(keycloak.refreshToken);
|
|
43
|
+
}
|
|
44
|
+
}, [keycloak?.authenticated, keycloak?.token, keycloak?.idToken, keycloak?.refreshToken]);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (authConfig.debug && keycloak?.token) logger.debug('token', keycloak.token);
|
|
48
|
+
}, [keycloak?.token]);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (authConfig.debug && keycloak?.idToken) logger.debug('idToken', keycloak.idToken);
|
|
52
|
+
}, [keycloak?.idToken]);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (authConfig.debug && keycloak?.refreshToken) logger.debug('refreshToken', keycloak.refreshToken);
|
|
56
|
+
}, [keycloak?.refreshToken]);
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (keycloak?.authenticated) logger.debug('authenticated', keycloak.authenticated);
|
|
60
|
+
}, [keycloak?.authenticated]);
|
|
61
|
+
|
|
62
|
+
return <>{children}</>;
|
|
63
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* File: /src/provider/
|
|
2
|
+
* File: /src/provider/AuthProvider/AuthProvider.native.tsx
|
|
3
3
|
* Project: @multiplatform.one/keycloak
|
|
4
|
-
* File Created:
|
|
4
|
+
* File Created: 09-01-2024 11:29:20
|
|
5
5
|
* Author: Clay Risser
|
|
6
6
|
* -----
|
|
7
|
-
* BitSpur (c) Copyright 2021 -
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
8
|
*
|
|
9
9
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
10
|
* you may not use this file except in compliance with the License.
|
|
@@ -20,22 +20,14 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import React from 'react';
|
|
23
|
-
import type {
|
|
24
|
-
import
|
|
25
|
-
import type { KeycloakProviderProps } from './keycloakProvider';
|
|
26
|
-
import { AfterAuth } from './afterAuth';
|
|
23
|
+
import type { AuthProviderProps } from './AuthProvider';
|
|
24
|
+
import { AfterAuth } from '../AfterAuth';
|
|
27
25
|
import { KeycloakProvider as ExpoKeycloakProvider } from 'expo-keycloak-auth';
|
|
28
26
|
|
|
29
|
-
export
|
|
30
|
-
const clonedKeycloakConfig = {
|
|
31
|
-
...(keycloakConfig as Omit<KeycloakConfig, 'baseUrl'>),
|
|
32
|
-
url: keycloakConfig.url,
|
|
33
|
-
};
|
|
34
|
-
// @ts-ignore
|
|
35
|
-
delete keycloakConfig.baseUrl;
|
|
27
|
+
export function AuthProvider({ children, keycloakConfig }: AuthProviderProps) {
|
|
36
28
|
return (
|
|
37
|
-
<ExpoKeycloakProvider {...
|
|
29
|
+
<ExpoKeycloakProvider {...keycloakConfig}>
|
|
38
30
|
<AfterAuth>{children}</AfterAuth>
|
|
39
31
|
</ExpoKeycloakProvider>
|
|
40
32
|
);
|
|
41
|
-
}
|
|
33
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* File: /src/provider/
|
|
2
|
+
* File: /src/provider/AuthProvider/AuthProvider.tsx
|
|
3
3
|
* Project: @multiplatform.one/keycloak
|
|
4
|
-
* File Created:
|
|
4
|
+
* File Created: 09-01-2024 11:29:20
|
|
5
5
|
* Author: Clay Risser
|
|
6
6
|
* -----
|
|
7
|
-
* BitSpur (c) Copyright 2021 -
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
8
|
*
|
|
9
9
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
10
|
* you may not use this file except in compliance with the License.
|
|
@@ -19,62 +19,56 @@
|
|
|
19
19
|
* limitations under the License.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import
|
|
23
|
-
import React, {
|
|
24
|
-
import type {
|
|
25
|
-
import type {
|
|
26
|
-
import type {
|
|
27
|
-
import { AfterAuth } from '
|
|
22
|
+
import KeycloakClient from 'keycloak-js';
|
|
23
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
24
|
+
import type { KeycloakConfig, KeycloakInitOptions } from 'keycloak-js';
|
|
25
|
+
import type { PropsWithChildren } from 'react';
|
|
26
|
+
import type { SessionProviderProps } from 'next-auth/react';
|
|
27
|
+
import { AfterAuth } from '../AfterAuth';
|
|
28
|
+
import { Keycloak } from '../../keycloak';
|
|
29
|
+
import { KeycloakContext } from '../../keycloak/context';
|
|
28
30
|
import { MultiPlatform } from 'multiplatform.one';
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import { useAuthConfig } from '
|
|
32
|
-
import { useAuthState } from '../state';
|
|
31
|
+
import { SessionProvider } from 'next-auth/react';
|
|
32
|
+
import { persist, useAuthState } from '../../state';
|
|
33
|
+
import { useAuthConfig } from '../../hooks';
|
|
33
34
|
import { useRouter } from 'next/router';
|
|
34
|
-
import { validToken } from '
|
|
35
|
+
import { validToken } from '../../token';
|
|
35
36
|
|
|
36
|
-
export interface
|
|
37
|
-
|
|
38
|
-
cookies?: unknown;
|
|
39
|
-
keycloakConfig: KeycloakConfig;
|
|
37
|
+
export interface AuthProviderProps extends PropsWithChildren {
|
|
38
|
+
keycloakConfig?: KeycloakConfig;
|
|
40
39
|
keycloakInitOptions?: KeycloakInitOptions;
|
|
41
|
-
|
|
42
|
-
onEvent?: (eventType: AuthClientEvent, error?: AuthClientError) => void;
|
|
43
|
-
onTokens?: (tokens: AuthClientTokens) => void;
|
|
40
|
+
sessionProvider?: Omit<SessionProviderProps, 'children'>;
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
const logger = console;
|
|
47
44
|
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
cookies,
|
|
51
|
-
keycloakConfig,
|
|
52
|
-
keycloakInitOptions,
|
|
53
|
-
loadingComponent,
|
|
54
|
-
onEvent,
|
|
55
|
-
onTokens,
|
|
56
|
-
}: KeycloakProviderProps) {
|
|
57
|
-
const { debug, ensureFreshness, persist, messageHandlerKeys, ssr } = useAuthConfig();
|
|
58
|
-
const authState = useAuthState();
|
|
59
|
-
const LoadingComponent = loadingComponent || (() => <>{debug ? 'authenticating' : null}</>);
|
|
45
|
+
export function AuthProvider({ children, sessionProvider, keycloakInitOptions, keycloakConfig }: AuthProviderProps) {
|
|
46
|
+
const { debug, messageHandlerKeys } = useAuthConfig();
|
|
60
47
|
const { query } = MultiPlatform.isNext ? useRouter() : { query: {} };
|
|
61
|
-
const
|
|
48
|
+
const authState = useAuthState();
|
|
49
|
+
const [keycloak, setKeycloak] = useState<Keycloak>();
|
|
50
|
+
const [refreshToken, setRefreshToken] = useState<string | boolean | undefined>(
|
|
62
51
|
validToken(
|
|
63
|
-
|
|
64
|
-
(
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
MultiPlatform.isIframe
|
|
53
|
+
? ('refreshToken' in query && (query.refreshToken?.toString() || true)) ||
|
|
54
|
+
(persist && authState.refreshToken) ||
|
|
55
|
+
false
|
|
56
|
+
: undefined,
|
|
67
57
|
),
|
|
68
58
|
);
|
|
69
|
-
const [
|
|
59
|
+
const [token, setToken] = useState<string | boolean | undefined>(
|
|
70
60
|
validToken(
|
|
71
|
-
|
|
61
|
+
MultiPlatform.isIframe
|
|
62
|
+
? ('token' in query && (query.token?.toString() || true)) || (persist && authState.token) || false
|
|
63
|
+
: undefined,
|
|
72
64
|
refreshToken,
|
|
73
65
|
),
|
|
74
66
|
);
|
|
75
|
-
const [
|
|
67
|
+
const [idToken, setIdToken] = useState<string | boolean | undefined>(
|
|
76
68
|
validToken(
|
|
77
|
-
|
|
69
|
+
MultiPlatform.isIframe
|
|
70
|
+
? ('idToken' in query && (query.idToken?.toString() || true)) || (persist && authState.idToken) || false
|
|
71
|
+
: undefined,
|
|
78
72
|
refreshToken,
|
|
79
73
|
),
|
|
80
74
|
);
|
|
@@ -188,28 +182,20 @@ export function KeycloakProvider({
|
|
|
188
182
|
};
|
|
189
183
|
}, []);
|
|
190
184
|
|
|
191
|
-
const
|
|
192
|
-
if (error) {
|
|
193
|
-
if (typeof error === 'string') throw new Error(error);
|
|
194
|
-
const err: Error & { errorDescription?: string } = new Error(error.error);
|
|
195
|
-
err.errorDescription = error.error_description;
|
|
196
|
-
throw err;
|
|
197
|
-
}
|
|
198
|
-
if (onEvent) onEvent(eventType, error);
|
|
199
|
-
}, []);
|
|
200
|
-
|
|
201
|
-
const keycloak = useMemo(
|
|
185
|
+
const keycloakClient = useMemo(
|
|
202
186
|
() =>
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
187
|
+
MultiPlatform.isIframe && keycloakConfig
|
|
188
|
+
? new KeycloakClient({
|
|
189
|
+
url: keycloakConfig.url,
|
|
190
|
+
realm: keycloakConfig.realm,
|
|
191
|
+
clientId: keycloakConfig.clientId,
|
|
192
|
+
})
|
|
193
|
+
: undefined,
|
|
194
|
+
[keycloakInitOptions, keycloakConfig, token, refreshToken, idToken],
|
|
210
195
|
);
|
|
211
196
|
|
|
212
197
|
const initOptions = useMemo(() => {
|
|
198
|
+
if (!MultiPlatform.isIframe) return;
|
|
213
199
|
const initOptions = {
|
|
214
200
|
...defaultKeycloakInitOptions,
|
|
215
201
|
...keycloakInitOptions,
|
|
@@ -227,45 +213,46 @@ export function KeycloakProvider({
|
|
|
227
213
|
initOptions.onLoad = undefined;
|
|
228
214
|
}
|
|
229
215
|
return initOptions;
|
|
230
|
-
}, [keycloakInitOptions, token,
|
|
216
|
+
}, [keycloakInitOptions, token, idToken, refreshToken]);
|
|
217
|
+
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
function onError() {
|
|
220
|
+
if (keycloakClient && initOptions) setKeycloak(new Keycloak(keycloakClient));
|
|
221
|
+
}
|
|
222
|
+
function onUpdate() {
|
|
223
|
+
if (keycloakClient && initOptions) setKeycloak(new Keycloak(keycloakClient));
|
|
224
|
+
}
|
|
225
|
+
if (keycloakClient && initOptions) {
|
|
226
|
+
(async () => {
|
|
227
|
+
keycloakClient.onAuthError = onError;
|
|
228
|
+
keycloakClient.onAuthLogout = onUpdate;
|
|
229
|
+
keycloakClient.onAuthRefreshError = onError;
|
|
230
|
+
keycloakClient.onAuthRefreshSuccess = onUpdate;
|
|
231
|
+
keycloakClient.onAuthSuccess = onUpdate;
|
|
232
|
+
keycloakClient.onReady = onUpdate;
|
|
233
|
+
keycloakClient.onTokenExpired = async () => {
|
|
234
|
+
try {
|
|
235
|
+
await keycloakClient.updateToken(5);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
setKeycloak(new Keycloak());
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
const authenticated = await keycloakClient.init(initOptions);
|
|
241
|
+
setKeycloak(new Keycloak(authenticated ? keycloakClient : undefined));
|
|
242
|
+
})();
|
|
243
|
+
}
|
|
244
|
+
}, []);
|
|
231
245
|
|
|
232
|
-
if (token === true || idToken === true || refreshToken === true) return <LoadingComponent />;
|
|
233
|
-
if (cookies && ssr) {
|
|
234
|
-
return (
|
|
235
|
-
// @ts-ignore
|
|
236
|
-
<SSRKeycloakProvider
|
|
237
|
-
LoadingComponent={<LoadingComponent />}
|
|
238
|
-
autoRefreshToken={initOptions.checkLoginIframe}
|
|
239
|
-
initOptions={initOptions}
|
|
240
|
-
onEvent={handleEvent}
|
|
241
|
-
onTokens={onTokens}
|
|
242
|
-
persistor={SSRCookies(cookies)}
|
|
243
|
-
keycloakConfig={{
|
|
244
|
-
clientId: keycloakConfig.clientId,
|
|
245
|
-
realm: keycloakConfig.realm,
|
|
246
|
-
url: keycloakConfig.url,
|
|
247
|
-
}}
|
|
248
|
-
>
|
|
249
|
-
<AfterAuth>{children}</AfterAuth>
|
|
250
|
-
</SSRKeycloakProvider>
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
if (!keycloak) return <LoadingComponent />;
|
|
254
246
|
return (
|
|
255
|
-
<
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
onEvent={handleEvent}
|
|
261
|
-
onTokens={onTokens}
|
|
262
|
-
>
|
|
263
|
-
<AfterAuth>{children}</AfterAuth>
|
|
264
|
-
</ReactKeycloakProvider>
|
|
247
|
+
<SessionProvider {...sessionProvider}>
|
|
248
|
+
<KeycloakContext.Provider value={keycloak}>
|
|
249
|
+
<AfterAuth>{children}</AfterAuth>
|
|
250
|
+
</KeycloakContext.Provider>
|
|
251
|
+
</SessionProvider>
|
|
265
252
|
);
|
|
266
253
|
}
|
|
267
254
|
|
|
268
|
-
|
|
255
|
+
const defaultKeycloakInitOptions: KeycloakInitOptions = {
|
|
269
256
|
checkLoginIframe: true,
|
|
270
257
|
checkLoginIframeInterval: 5,
|
|
271
258
|
enableLogging: false,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* File: /src
|
|
2
|
+
* File: /src/provider/AuthProvider/index.ts
|
|
3
3
|
* Project: @multiplatform.one/keycloak
|
|
4
|
-
* File Created:
|
|
4
|
+
* File Created: 10-01-2024 13:43:20
|
|
5
5
|
* Author: Clay Risser
|
|
6
6
|
* -----
|
|
7
|
-
* BitSpur (c) Copyright 2021 -
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
8
|
*
|
|
9
9
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
10
|
* you may not use this file except in compliance with the License.
|
|
@@ -19,7 +19,4 @@
|
|
|
19
19
|
* limitations under the License.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
export function useKeycloak(): any;
|
|
24
|
-
export const KeycloakProvider: any;
|
|
25
|
-
}
|
|
22
|
+
export * from './AuthProvider';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/provider/KeycloakProvider.tsx
|
|
3
|
+
* Project: @multiplatform.one/keycloak
|
|
4
|
+
* File Created: 10-01-2024 13:56:05
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import React, { useMemo } from 'react';
|
|
23
|
+
import type { AuthConfig } from '../authConfig';
|
|
24
|
+
import type { PropsWithChildren } from 'react';
|
|
25
|
+
import type { Session } from 'next-auth';
|
|
26
|
+
import { AuthConfigContext } from '../authConfig';
|
|
27
|
+
import { AuthProvider } from './AuthProvider';
|
|
28
|
+
|
|
29
|
+
export interface KeycloakProviderProps extends PropsWithChildren, AuthConfig {
|
|
30
|
+
baseUrl?: string;
|
|
31
|
+
clientId?: string;
|
|
32
|
+
realm?: string;
|
|
33
|
+
session?: Session;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function KeycloakProvider({ children, debug, realm, clientId, baseUrl, session }: KeycloakProviderProps) {
|
|
37
|
+
const authConfig = useMemo(() => ({ debug }), [debug]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<AuthConfigContext.Provider value={authConfig}>
|
|
41
|
+
<AuthProvider
|
|
42
|
+
sessionProvider={{ session }}
|
|
43
|
+
keycloakConfig={{
|
|
44
|
+
realm: realm || 'main',
|
|
45
|
+
clientId: clientId || 'app',
|
|
46
|
+
url: baseUrl,
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
{children}
|
|
50
|
+
</AuthProvider>
|
|
51
|
+
</AuthConfigContext.Provider>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* File: /src/
|
|
2
|
+
* File: /src/provider/index.ts
|
|
3
3
|
* Project: @multiplatform.one/keycloak
|
|
4
|
-
* File Created:
|
|
4
|
+
* File Created: 09-01-2024 11:29:13
|
|
5
5
|
* Author: Clay Risser
|
|
6
6
|
* -----
|
|
7
|
-
* BitSpur (c) Copyright 2021 -
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
8
|
*
|
|
9
9
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
10
|
* you may not use this file except in compliance with the License.
|
|
@@ -19,11 +19,6 @@
|
|
|
19
19
|
* limitations under the License.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export function useCurrentRouteName() {
|
|
26
|
-
if (MultiPlatform.isStorybook) return null;
|
|
27
|
-
const route = useRoute();
|
|
28
|
-
return route.name;
|
|
29
|
-
}
|
|
22
|
+
export * from './AfterAuth';
|
|
23
|
+
export * from './AuthProvider';
|
|
24
|
+
export * from './KeycloakProvider';
|
package/src/routes.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: /src/routes.ts
|
|
3
|
+
* Project: @multiplatform.one/keycloak
|
|
4
|
+
* File Created: 09-01-2024 11:32:46
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { AccessTokenParsed } from './token';
|
|
23
|
+
import type { AuthOptions, CallbacksOptions } from 'next-auth';
|
|
24
|
+
import type { JWT } from 'next-auth/jwt';
|
|
25
|
+
import type { OAuthUserConfig } from 'next-auth/providers';
|
|
26
|
+
import type { Session } from './session';
|
|
27
|
+
import { getServerSession } from 'next-auth';
|
|
28
|
+
import { jwtDecode } from 'jwt-decode';
|
|
29
|
+
|
|
30
|
+
const KeycloakProvider = require('next-auth/providers/keycloak').default;
|
|
31
|
+
const NextAuth = require('next-auth').default;
|
|
32
|
+
const NextResponse = require('next/server').NextResponse;
|
|
33
|
+
|
|
34
|
+
const logger = console;
|
|
35
|
+
let _nextAuth: AuthOptions | undefined;
|
|
36
|
+
|
|
37
|
+
export function createAuthHandler(options: CreateAuthHandlerOptions = {}) {
|
|
38
|
+
const handler = NextAuth(createAuthOptions(options));
|
|
39
|
+
return {
|
|
40
|
+
GET: handler,
|
|
41
|
+
POST: handler,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function createLogoutHandler(options: CreateAuthHandlerOptions = {}) {
|
|
46
|
+
return {
|
|
47
|
+
async GET() {
|
|
48
|
+
const idToken = ((await getServerSession(createAuthOptions(options))) as Session)?.idToken;
|
|
49
|
+
if (idToken) {
|
|
50
|
+
try {
|
|
51
|
+
await fetch(
|
|
52
|
+
`${process.env.KEYCLOAK_BASE_URL}/realms/${
|
|
53
|
+
process.env.KEYCLOAK_REALM || 'master'
|
|
54
|
+
}/protocol/openid-connect/logout?id_token_hint=${idToken}&post_logout_redirect_uri=${encodeURIComponent(
|
|
55
|
+
process.env.NEXTAUTH_URL || '',
|
|
56
|
+
)}`,
|
|
57
|
+
{ method: 'GET' },
|
|
58
|
+
);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
logger.error(err);
|
|
61
|
+
return new NextResponse(null, { status: 500 });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return new NextResponse();
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function createAuthOptions(options: CreateAuthHandlerOptions = {}) {
|
|
70
|
+
if (_nextAuth) return _nextAuth;
|
|
71
|
+
_nextAuth = {
|
|
72
|
+
...options.nextAuth,
|
|
73
|
+
providers: [
|
|
74
|
+
KeycloakProvider({
|
|
75
|
+
clientId: process.env.KEYCLOAK_CLIENT_ID || '',
|
|
76
|
+
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || '',
|
|
77
|
+
issuer: `${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM || 'master'}`,
|
|
78
|
+
...options.keycloakProvider,
|
|
79
|
+
}),
|
|
80
|
+
...(options.nextAuth?.providers || []),
|
|
81
|
+
],
|
|
82
|
+
callbacks: {
|
|
83
|
+
...options.nextAuth?.callbacks,
|
|
84
|
+
async jwt(params) {
|
|
85
|
+
if (typeof options.nextAuth?.callbacks?.jwt === 'function') {
|
|
86
|
+
return options.nextAuth?.callbacks.jwt(params);
|
|
87
|
+
}
|
|
88
|
+
const { token, account } = params;
|
|
89
|
+
if (account) {
|
|
90
|
+
const decoded = jwtDecode(account.access_token || '') as AccessTokenParsed;
|
|
91
|
+
token.decoded = decoded;
|
|
92
|
+
token.accessToken = account.access_token;
|
|
93
|
+
token.idToken = account.id_token;
|
|
94
|
+
token.expiresAt = account.expires_at;
|
|
95
|
+
token.refreshToken = account.refresh_token;
|
|
96
|
+
token.roles = decoded.realm_access?.roles;
|
|
97
|
+
return token;
|
|
98
|
+
} else if (Math.floor(Date.now() / 1000) < Number(token.expiresAt)) {
|
|
99
|
+
return token;
|
|
100
|
+
} else {
|
|
101
|
+
try {
|
|
102
|
+
return refreshAccessToken(token as NextToken);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
return { ...token, err };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
async session(params) {
|
|
109
|
+
if (typeof options.nextAuth?.callbacks?.session === 'function') {
|
|
110
|
+
return options.nextAuth.callbacks.session(params);
|
|
111
|
+
}
|
|
112
|
+
const { session: nextSession, token: nextToken } = params;
|
|
113
|
+
const session = nextSession as Session;
|
|
114
|
+
const token = nextToken as NextToken;
|
|
115
|
+
if (token.accessToken) session.accessToken = token.accessToken;
|
|
116
|
+
if (token.idToken) session.idToken = token.idToken;
|
|
117
|
+
session.err = token.err;
|
|
118
|
+
return session;
|
|
119
|
+
},
|
|
120
|
+
} as CallbacksOptions,
|
|
121
|
+
} as AuthOptions;
|
|
122
|
+
return _nextAuth;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function refreshAccessToken(nextToken: NextToken) {
|
|
126
|
+
const res = await fetch(process.env.REFRESH_TOKEN_URL || '', {
|
|
127
|
+
method: 'POST',
|
|
128
|
+
headers: {
|
|
129
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
130
|
+
},
|
|
131
|
+
body: new URLSearchParams({
|
|
132
|
+
client_id: process.env.KEYCLOAK_CLIENT_ID || '',
|
|
133
|
+
client_secret: process.env.KEYCLOAK_CLIENT_SECRET || '',
|
|
134
|
+
grant_type: 'refresh_token',
|
|
135
|
+
refresh_token: nextToken.refreshToken,
|
|
136
|
+
}),
|
|
137
|
+
});
|
|
138
|
+
const refreshToken = await res.json();
|
|
139
|
+
if (!res.ok) throw refreshToken;
|
|
140
|
+
return {
|
|
141
|
+
...nextToken,
|
|
142
|
+
accessToken: refreshToken.access_token,
|
|
143
|
+
decoded: jwtDecode(refreshToken.access_token),
|
|
144
|
+
expiresAt: Math.floor(Date.now() / 1000) + Number(refreshToken.expires_in),
|
|
145
|
+
idToken: refreshToken.id_token,
|
|
146
|
+
refreshToken: refreshToken.refresh_token,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface CreateAuthHandlerOptions {
|
|
151
|
+
keycloakProvider?: Partial<OAuthUserConfig<any>>;
|
|
152
|
+
nextAuth?: AuthOptions;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface NextToken extends JWT {
|
|
156
|
+
accessToken?: string;
|
|
157
|
+
decoded: AccessTokenParsed;
|
|
158
|
+
err?: Error;
|
|
159
|
+
expiresAt: number;
|
|
160
|
+
idToken?: string;
|
|
161
|
+
refreshToken: string;
|
|
162
|
+
roles: string[];
|
|
163
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: /src/session/index.ts
|
|
3
|
+
* Project: @multiplatform.one/keycloak
|
|
4
|
+
* File Created: 11-01-2024 02:47:42
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export * from './session';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: /src/session/session.native.ts
|
|
3
|
+
* Project: @multiplatform.one/keycloak
|
|
4
|
+
* File Created: 10-01-2024 02:31:26
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* BitSpur (c) Copyright 2021 - 2024
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { SessionContextValue } from './session';
|
|
23
|
+
import type { UseSessionOptions } from 'next-auth/react';
|
|
24
|
+
|
|
25
|
+
export async function getSession() {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function useSession<R extends boolean>(_options?: UseSessionOptions<R>): SessionContextValue<R> {
|
|
30
|
+
return {};
|
|
31
|
+
}
|