@axa-fr/react-oidc 6.6.0 → 6.6.2-alpha0
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 +2 -1
- package/src/App.css +38 -0
- package/src/App.specold.tsx +46 -0
- package/src/App.tsx +103 -0
- package/src/FetchUser.tsx +53 -0
- package/src/Home.tsx +24 -0
- package/src/MultiAuth.tsx +129 -0
- package/src/Profile.tsx +77 -0
- package/src/configurations.ts +70 -0
- package/src/index.css +13 -0
- package/src/index.tsx +9 -0
- package/src/logo.svg +7 -0
- package/src/oidc/FetchToken.tsx +61 -0
- package/src/oidc/OidcProvider.tsx +206 -0
- package/src/oidc/OidcSecure.tsx +37 -0
- package/src/oidc/ReactOidc.tsx +139 -0
- package/src/oidc/User.ts +38 -0
- package/src/oidc/core/default-component/AuthenticateError.component.tsx +13 -0
- package/src/oidc/core/default-component/Authenticating.component.tsx +13 -0
- package/src/oidc/core/default-component/Callback.component.tsx +46 -0
- package/src/oidc/core/default-component/Loading.component.tsx +10 -0
- package/src/oidc/core/default-component/ServiceWorkerNotSupported.component.tsx +13 -0
- package/src/oidc/core/default-component/SessionLost.component.tsx +14 -0
- package/src/oidc/core/default-component/SilentCallback.component.tsx +22 -0
- package/src/oidc/core/default-component/SilentLogin.component.tsx +35 -0
- package/src/oidc/core/default-component/index.ts +6 -0
- package/src/oidc/core/routes/OidcRoutes.spec.tsx +15 -0
- package/src/oidc/core/routes/OidcRoutes.tsx +69 -0
- package/src/oidc/core/routes/__snapshots__/OidcRoutes.spec.tsx.snap +7 -0
- package/src/oidc/core/routes/index.ts +2 -0
- package/src/oidc/core/routes/withRouter.spec.tsx +48 -0
- package/src/oidc/core/routes/withRouter.tsx +64 -0
- package/src/oidc/index.ts +5 -0
- package/src/oidc/vanilla/OidcServiceWorker.js +442 -0
- package/src/oidc/vanilla/OidcTrustedDomains.js +16 -0
- package/src/oidc/vanilla/checkSessionIFrame.ts +82 -0
- package/src/oidc/vanilla/index.ts +1 -0
- package/src/oidc/vanilla/initSession.ts +67 -0
- package/src/oidc/vanilla/initWorker.ts +165 -0
- package/src/oidc/vanilla/memoryStorageBackend.ts +33 -0
- package/src/oidc/vanilla/noHashQueryStringUtils.ts +33 -0
- package/src/oidc/vanilla/oidc.ts +1230 -0
- package/src/oidc/vanilla/parseTokens.ts +142 -0
- package/src/oidc/vanilla/route-utils.spec.ts +15 -0
- package/src/oidc/vanilla/route-utils.ts +76 -0
- package/src/oidc/vanilla/timer.ts +165 -0
- package/src/override/AuthenticateError.component.tsx +14 -0
- package/src/override/Authenticating.component.tsx +14 -0
- package/src/override/Callback.component.tsx +13 -0
- package/src/override/Loading.component.tsx +13 -0
- package/src/override/ServiceWorkerNotSupported.component.tsx +15 -0
- package/src/override/SessionLost.component.tsx +21 -0
- package/src/override/style.ts +10 -0
- package/src/setupTests.js +5 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Oidc from "./vanilla/oidc";
|
|
3
|
+
import {isTokensValid} from "./vanilla/parseTokens";
|
|
4
|
+
import {sleepAsync} from "./vanilla/initWorker";
|
|
5
|
+
|
|
6
|
+
export type Fetch = typeof window.fetch;
|
|
7
|
+
export interface ComponentWithOidcFetchProps {
|
|
8
|
+
fetch?: Fetch;
|
|
9
|
+
}
|
|
10
|
+
const defaultConfigurationName = "default";
|
|
11
|
+
|
|
12
|
+
const fetchWithToken = (fetch: Fetch, getOidcWithConfigurationName: () => Oidc | null) => async (
|
|
13
|
+
url: RequestInfo,
|
|
14
|
+
options: RequestInit = { method: 'GET' }
|
|
15
|
+
) => {
|
|
16
|
+
let headers = new Headers();
|
|
17
|
+
const optionTmp = { ...options };
|
|
18
|
+
|
|
19
|
+
if (optionTmp.headers) {
|
|
20
|
+
headers = !(optionTmp.headers instanceof Headers)
|
|
21
|
+
? new Headers(optionTmp.headers)
|
|
22
|
+
: optionTmp.headers;
|
|
23
|
+
}
|
|
24
|
+
const oidc = getOidcWithConfigurationName();
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
const accessToken = oidc.tokens ? oidc.tokens.accessToken : null;
|
|
30
|
+
// We wait the synchronisation before making a request
|
|
31
|
+
while (oidc.tokens && accessToken && !isTokensValid(oidc.tokens)){
|
|
32
|
+
await sleepAsync(200);
|
|
33
|
+
}
|
|
34
|
+
if (!headers.has('Accept')) {
|
|
35
|
+
headers.set('Accept', 'application/json');
|
|
36
|
+
}
|
|
37
|
+
if (accessToken) {
|
|
38
|
+
headers.set('Authorization', `Bearer ${accessToken}`);
|
|
39
|
+
if (!optionTmp.credentials) {
|
|
40
|
+
optionTmp.credentials = 'same-origin';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const newOptions = { ...optionTmp, headers };
|
|
44
|
+
return await fetch(url, newOptions);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const withOidcFetch = (fetch:Fetch=null, configurationName=defaultConfigurationName) => (
|
|
48
|
+
WrappedComponent
|
|
49
|
+
) => (props: ComponentWithOidcFetchProps) => {
|
|
50
|
+
const {fetch:newFetch} = useOidcFetch(fetch || props.fetch, configurationName)
|
|
51
|
+
return <WrappedComponent {...props} fetch={newFetch} />;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
export const useOidcFetch =(fetch:Fetch=null, configurationName=defaultConfigurationName) =>{
|
|
56
|
+
const previousFetch = fetch || window.fetch;
|
|
57
|
+
const getOidc = Oidc.get;
|
|
58
|
+
const getOidcWithConfigurationName = () => { return getOidc(configurationName); };
|
|
59
|
+
const newFetch = fetchWithToken(previousFetch, getOidcWithConfigurationName);
|
|
60
|
+
return { fetch:newFetch };
|
|
61
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import React, {ComponentType, FC, PropsWithChildren, useEffect, useState} from 'react';
|
|
2
|
+
import Oidc, {OidcConfiguration} from './vanilla/oidc';
|
|
3
|
+
import OidcRoutes from './core/routes/OidcRoutes';
|
|
4
|
+
import {Authenticating, AuthenticateError, SessionLost, Loading, CallBackSuccess} from './core/default-component/index';
|
|
5
|
+
import ServiceWorkerNotSupported from "./core/default-component/ServiceWorkerNotSupported.component";
|
|
6
|
+
import AuthenticatingError from "./core/default-component/AuthenticateError.component";
|
|
7
|
+
import { CustomHistory } from "./core/routes/withRouter";
|
|
8
|
+
|
|
9
|
+
export type oidcContext = {
|
|
10
|
+
getOidc: Function;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const defaultEventState = {name:"", data:null};
|
|
14
|
+
|
|
15
|
+
export type OidcProviderProps = {
|
|
16
|
+
callbackSuccessComponent?: ComponentType<any>;
|
|
17
|
+
sessionLostComponent?: ComponentType<any>;
|
|
18
|
+
authenticatingComponent?: ComponentType<any>;
|
|
19
|
+
authenticatingErrorComponent?: ComponentType<any>;
|
|
20
|
+
loadingComponent?: ComponentType<any>;
|
|
21
|
+
serviceWorkerNotSupportedComponent?: ComponentType<any>;
|
|
22
|
+
configurationName?: string;
|
|
23
|
+
configuration?: OidcConfiguration;
|
|
24
|
+
children: any;
|
|
25
|
+
onSessionLost?: Function,
|
|
26
|
+
onLogoutFromAnotherTab?:Function,
|
|
27
|
+
onLogoutFromSameTab?:Function,
|
|
28
|
+
withCustomHistory?: () => CustomHistory,
|
|
29
|
+
onEvent?:Function
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type OidcSessionProps = {
|
|
33
|
+
configurationName: string;
|
|
34
|
+
loadingComponent: PropsWithChildren<any>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
const OidcSession : FC<PropsWithChildren<OidcSessionProps>> = ({loadingComponent, children, configurationName}) =>{
|
|
39
|
+
const [loading, setLoading] = useState(true);
|
|
40
|
+
const getOidc = Oidc.get;
|
|
41
|
+
const oidc = getOidc(configurationName);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
let isMounted = true;
|
|
44
|
+
if(oidc) {
|
|
45
|
+
oidc.tryKeepExistingSessionAsync().then(() => {
|
|
46
|
+
if (isMounted) {
|
|
47
|
+
setLoading(false);
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
return () => {
|
|
52
|
+
isMounted = false;
|
|
53
|
+
}
|
|
54
|
+
}, [oidc, configurationName]);
|
|
55
|
+
const LoadingComponent = loadingComponent;
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
{loading ? (
|
|
59
|
+
<LoadingComponent configurationName={configurationName}/>
|
|
60
|
+
) : (
|
|
61
|
+
<>{children}</>
|
|
62
|
+
)}
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const Switch = ({isLoading, loadingComponent, children, configurationName}) => {
|
|
68
|
+
const LoadingComponent = loadingComponent;
|
|
69
|
+
if(isLoading){
|
|
70
|
+
return <LoadingComponent configurationName={configurationName}>{children}</LoadingComponent>;
|
|
71
|
+
}
|
|
72
|
+
return <>{children}</>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
export const OidcProvider : FC<PropsWithChildren<OidcProviderProps>> = ({ children,
|
|
77
|
+
configuration,
|
|
78
|
+
configurationName = "default",
|
|
79
|
+
callbackSuccessComponent = CallBackSuccess,
|
|
80
|
+
authenticatingComponent = Authenticating,
|
|
81
|
+
loadingComponent = Loading,
|
|
82
|
+
serviceWorkerNotSupportedComponent = ServiceWorkerNotSupported,
|
|
83
|
+
authenticatingErrorComponent = AuthenticatingError,
|
|
84
|
+
sessionLostComponent=SessionLost,
|
|
85
|
+
onSessionLost=null,
|
|
86
|
+
onLogoutFromAnotherTab=null,
|
|
87
|
+
onLogoutFromSameTab=null,
|
|
88
|
+
withCustomHistory=null,
|
|
89
|
+
onEvent=null,
|
|
90
|
+
}) => {
|
|
91
|
+
const getOidc =(configurationName="default") => {
|
|
92
|
+
return Oidc.getOrCreate(configuration, configurationName);
|
|
93
|
+
}
|
|
94
|
+
const [loading, setLoading] = useState(true);
|
|
95
|
+
const [event, setEvent] = useState(defaultEventState);
|
|
96
|
+
const [currentConfigurationName, setConfigurationName] = useState("default");
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
const oidc = getOidc(configurationName);
|
|
100
|
+
const newSubscriptionId = oidc.subscriveEvents((name, data) => {
|
|
101
|
+
if(onEvent)
|
|
102
|
+
{
|
|
103
|
+
onEvent(configurationName, name, data);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
return () => {
|
|
107
|
+
const previousOidc = getOidc(configurationName);
|
|
108
|
+
previousOidc.removeEventSubscription(newSubscriptionId);
|
|
109
|
+
}
|
|
110
|
+
}, [configurationName, onEvent]);
|
|
111
|
+
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
const oidc = getOidc(configurationName);
|
|
114
|
+
const newSubscriptionId = oidc.subscriveEvents((name, data) => {
|
|
115
|
+
if(name == Oidc.eventNames.refreshTokensAsync_error || name == Oidc.eventNames.syncTokensAsync_error){
|
|
116
|
+
if(onSessionLost != null){
|
|
117
|
+
onSessionLost();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
setEvent({name, data});
|
|
121
|
+
}
|
|
122
|
+
else if(name === Oidc.eventNames.logout_from_another_tab){
|
|
123
|
+
if(onLogoutFromAnotherTab != null){
|
|
124
|
+
onLogoutFromAnotherTab();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
setEvent({name, data});
|
|
128
|
+
}
|
|
129
|
+
else if(name === Oidc.eventNames.logout_from_same_tab){
|
|
130
|
+
if(onLogoutFromSameTab != null){
|
|
131
|
+
onLogoutFromSameTab();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
//setEvent({name, data});
|
|
135
|
+
}
|
|
136
|
+
else if (name == Oidc.eventNames.loginAsync_begin
|
|
137
|
+
|| name == Oidc.eventNames.loginCallbackAsync_end
|
|
138
|
+
|| name == Oidc.eventNames.loginAsync_error
|
|
139
|
+
|| name == Oidc.eventNames.loginCallbackAsync_error
|
|
140
|
+
) {
|
|
141
|
+
setEvent({name, data});
|
|
142
|
+
} else if (name == Oidc.eventNames.service_worker_not_supported_by_browser && configuration.service_worker_only === true) {
|
|
143
|
+
setEvent({name, data});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
setConfigurationName(configurationName);
|
|
148
|
+
setLoading(false);
|
|
149
|
+
return () => {
|
|
150
|
+
const previousOidc = getOidc(configurationName);
|
|
151
|
+
previousOidc.removeEventSubscription(newSubscriptionId);
|
|
152
|
+
setEvent(defaultEventState);
|
|
153
|
+
}
|
|
154
|
+
}, [configuration, configurationName]);
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
const SessionLostComponent = sessionLostComponent;
|
|
158
|
+
const AuthenticatingComponent = authenticatingComponent;
|
|
159
|
+
const LoadingComponent = loadingComponent;
|
|
160
|
+
const ServiceWorkerNotSupportedComponent = serviceWorkerNotSupportedComponent;
|
|
161
|
+
const AuthenticatingErrorComponent = authenticatingErrorComponent;
|
|
162
|
+
|
|
163
|
+
const isLoading = (loading || (currentConfigurationName != configurationName ));
|
|
164
|
+
const oidc = getOidc(configurationName);
|
|
165
|
+
let eventName = event.name;
|
|
166
|
+
switch(eventName){
|
|
167
|
+
case Oidc.eventNames.service_worker_not_supported_by_browser:
|
|
168
|
+
return <Switch loadingComponent={LoadingComponent} isLoading={isLoading} configurationName={configurationName}>
|
|
169
|
+
<ServiceWorkerNotSupportedComponent configurationName={configurationName} />
|
|
170
|
+
</Switch>;
|
|
171
|
+
case Oidc.eventNames.loginAsync_begin:
|
|
172
|
+
return <Switch loadingComponent={LoadingComponent} isLoading={isLoading} configurationName={configurationName}>
|
|
173
|
+
<AuthenticatingComponent configurationName={configurationName} />
|
|
174
|
+
</Switch>;
|
|
175
|
+
case Oidc.eventNames.loginAsync_error:
|
|
176
|
+
case Oidc.eventNames.loginCallbackAsync_error:
|
|
177
|
+
return <Switch loadingComponent={LoadingComponent} isLoading={isLoading} configurationName={configurationName}>
|
|
178
|
+
<AuthenticatingErrorComponent configurationName={configurationName} />
|
|
179
|
+
</Switch>;
|
|
180
|
+
case Oidc.eventNames.refreshTokensAsync_error:
|
|
181
|
+
case Oidc.eventNames.syncTokensAsync_error:
|
|
182
|
+
case Oidc.eventNames.logout_from_another_tab:
|
|
183
|
+
return <Switch loadingComponent={LoadingComponent} isLoading={isLoading} configurationName={configurationName}>
|
|
184
|
+
<SessionLostComponent configurationName={configurationName} />
|
|
185
|
+
</Switch>;
|
|
186
|
+
default:
|
|
187
|
+
return (
|
|
188
|
+
<Switch loadingComponent={LoadingComponent} isLoading={isLoading} configurationName={configurationName}>
|
|
189
|
+
<OidcRoutes redirect_uri={oidc.configuration.redirect_uri}
|
|
190
|
+
silent_redirect_uri={oidc.configuration.silent_redirect_uri}
|
|
191
|
+
silent_login_uri={oidc.configuration.silent_login_uri}
|
|
192
|
+
callbackSuccessComponent={callbackSuccessComponent}
|
|
193
|
+
callbackErrorComponent={authenticatingErrorComponent}
|
|
194
|
+
authenticatingComponent={authenticatingComponent}
|
|
195
|
+
configurationName={configurationName}
|
|
196
|
+
withCustomHistory={withCustomHistory}>
|
|
197
|
+
<OidcSession loadingComponent={LoadingComponent} configurationName={configurationName}>
|
|
198
|
+
{children}
|
|
199
|
+
</OidcSession>
|
|
200
|
+
</OidcRoutes>
|
|
201
|
+
</Switch>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
export default OidcProvider;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React, {useEffect, PropsWithChildren, FC} from 'react';
|
|
2
|
+
|
|
3
|
+
import Oidc, {StringMap} from "./vanilla/oidc";
|
|
4
|
+
|
|
5
|
+
export type OidcSecureProps = {
|
|
6
|
+
callbackPath?:string;
|
|
7
|
+
extras?:StringMap
|
|
8
|
+
configurationName?: string;
|
|
9
|
+
state?: string|undefined;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const OidcSecure: FC<PropsWithChildren<OidcSecureProps>> = ({children, callbackPath=null, extras=null, configurationName="default"}) => {
|
|
13
|
+
const getOidc = Oidc.get;
|
|
14
|
+
const oidc = getOidc(configurationName);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if(!oidc.tokens){
|
|
17
|
+
oidc.loginAsync(callbackPath, extras);
|
|
18
|
+
}
|
|
19
|
+
return () => {
|
|
20
|
+
}
|
|
21
|
+
}, [configurationName, callbackPath, extras])
|
|
22
|
+
|
|
23
|
+
if(!oidc.tokens){
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return <>{children}</>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const withOidcSecure = (
|
|
30
|
+
WrappedComponent: FC<PropsWithChildren<OidcSecureProps>>,
|
|
31
|
+
callbackPath=null,
|
|
32
|
+
extras=null,
|
|
33
|
+
configurationName="default",
|
|
34
|
+
state: string|undefined=undefined
|
|
35
|
+
) => (props) => {
|
|
36
|
+
return <OidcSecure state={state} callbackPath={callbackPath} extras={extras} configurationName={configurationName}><WrappedComponent {...props} /></OidcSecure>;
|
|
37
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React, {useEffect, useState} from 'react';
|
|
2
|
+
import Oidc, {StringMap} from "./vanilla/oidc";
|
|
3
|
+
|
|
4
|
+
const defaultConfigurationName = "default";
|
|
5
|
+
|
|
6
|
+
const defaultIsAuthenticated = (getOidc, configurationName) =>{
|
|
7
|
+
let isAuthenticated:boolean = false;
|
|
8
|
+
const oidc = getOidc(configurationName);
|
|
9
|
+
if(oidc){
|
|
10
|
+
isAuthenticated = getOidc(configurationName).tokens != null;
|
|
11
|
+
}
|
|
12
|
+
return isAuthenticated;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const useOidc =(configurationName=defaultConfigurationName) =>{
|
|
16
|
+
const getOidc = Oidc.get;
|
|
17
|
+
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(defaultIsAuthenticated(getOidc, configurationName));
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
let isMounted = true;
|
|
21
|
+
const oidc = getOidc(configurationName);
|
|
22
|
+
setIsAuthenticated(defaultIsAuthenticated(getOidc, configurationName));
|
|
23
|
+
const newSubscriptionId = oidc.subscriveEvents((name, data) => {
|
|
24
|
+
if(name === Oidc.eventNames.logout_from_another_tab || name === Oidc.eventNames.logout_from_same_tab || name === Oidc.eventNames.token_aquired){
|
|
25
|
+
if(isMounted) {
|
|
26
|
+
setIsAuthenticated(defaultIsAuthenticated(getOidc, configurationName));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return () => {
|
|
31
|
+
isMounted = false;
|
|
32
|
+
oidc.removeEventSubscription(newSubscriptionId);
|
|
33
|
+
};
|
|
34
|
+
}, [configurationName]);
|
|
35
|
+
|
|
36
|
+
const login = (callbackPath:string | undefined = undefined, extras:StringMap=null, silentLoginOnly = false) => {
|
|
37
|
+
return getOidc(configurationName).loginAsync(callbackPath, extras, false, undefined, silentLoginOnly);
|
|
38
|
+
};
|
|
39
|
+
const logout = (callbackPath: string | null | undefined = undefined, extras:StringMap=null) => {
|
|
40
|
+
return getOidc(configurationName).logoutAsync(callbackPath, extras);
|
|
41
|
+
};
|
|
42
|
+
const renewTokens = (extras:StringMap=null) => {
|
|
43
|
+
return getOidc(configurationName).renewTokensAsync(extras);
|
|
44
|
+
};
|
|
45
|
+
return { login, logout, renewTokens, isAuthenticated };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const accessTokenInitialState = {accessToken:null, accessTokenPayload:null};
|
|
49
|
+
|
|
50
|
+
const initTokens = (configurationName) => {
|
|
51
|
+
const getOidc = Oidc.get;
|
|
52
|
+
const oidc = getOidc(configurationName);
|
|
53
|
+
if(oidc.tokens) {
|
|
54
|
+
const tokens = oidc.tokens;
|
|
55
|
+
return {accessToken :tokens.accessToken, accessTokenPayload: tokens.accessTokenPayload }
|
|
56
|
+
}
|
|
57
|
+
return accessTokenInitialState;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type OidcAccessToken = {
|
|
61
|
+
accessToken?: any,
|
|
62
|
+
accessTokenPayload?: any
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const useOidcAccessToken =(configurationName=defaultConfigurationName) =>{
|
|
66
|
+
const getOidc = Oidc.get;
|
|
67
|
+
const [state, setAccessToken] = useState<OidcAccessToken>(initTokens(configurationName));
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
let isMounted = true;
|
|
71
|
+
const oidc = getOidc(configurationName);
|
|
72
|
+
if(oidc.tokens) {
|
|
73
|
+
const tokens = oidc.tokens;
|
|
74
|
+
setAccessToken({accessToken :tokens.accessToken, accessTokenPayload: tokens.accessTokenPayload });
|
|
75
|
+
}
|
|
76
|
+
const newSubscriptionId = oidc.subscriveEvents((name, data) => {
|
|
77
|
+
if(name == Oidc.eventNames.token_renewed
|
|
78
|
+
|| name == Oidc.eventNames.token_aquired
|
|
79
|
+
|| name === Oidc.eventNames.logout_from_another_tab
|
|
80
|
+
|| name === Oidc.eventNames.logout_from_same_tab){
|
|
81
|
+
if(isMounted) {
|
|
82
|
+
const tokens = oidc.tokens;
|
|
83
|
+
setAccessToken(tokens != null ? {accessToken :tokens.accessToken, accessTokenPayload: tokens.accessTokenPayload } : accessTokenInitialState);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
return () => {
|
|
88
|
+
isMounted = false;
|
|
89
|
+
oidc.removeEventSubscription(newSubscriptionId);
|
|
90
|
+
};
|
|
91
|
+
}, [configurationName]);
|
|
92
|
+
return state;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const idTokenInitialState = {idToken:null, idTokenPayload:null};
|
|
96
|
+
|
|
97
|
+
const initIdToken= (configurationName) =>{
|
|
98
|
+
const getOidc = Oidc.get;
|
|
99
|
+
const oidc = getOidc(configurationName);
|
|
100
|
+
if(oidc.tokens) {
|
|
101
|
+
const tokens = oidc.tokens;
|
|
102
|
+
return { idToken: tokens.idToken, idTokenPayload:tokens.idTokenPayload };
|
|
103
|
+
}
|
|
104
|
+
return idTokenInitialState
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type OidcIdToken = {
|
|
108
|
+
idToken?: any,
|
|
109
|
+
idTokenPayload?: any
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export const useOidcIdToken =(configurationName= defaultConfigurationName) =>{
|
|
113
|
+
const getOidc = Oidc.get;
|
|
114
|
+
const [state, setIDToken] = useState<OidcIdToken>(initIdToken(configurationName));
|
|
115
|
+
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
let isMounted = true;
|
|
118
|
+
const oidc = getOidc(configurationName);
|
|
119
|
+
if(oidc.tokens) {
|
|
120
|
+
const tokens = oidc.tokens;
|
|
121
|
+
setIDToken({idToken: tokens.idToken, idTokenPayload:tokens.idTokenPayload});
|
|
122
|
+
}
|
|
123
|
+
const newSubscriptionId = oidc.subscriveEvents((name, data) => {
|
|
124
|
+
if(name == Oidc.eventNames.token_renewed
|
|
125
|
+
|| name == Oidc.eventNames.token_aquired
|
|
126
|
+
|| name === Oidc.eventNames.logout_from_another_tab){
|
|
127
|
+
if(isMounted) {
|
|
128
|
+
const tokens = oidc.tokens;
|
|
129
|
+
setIDToken(tokens != null ? {idToken: tokens.idToken, idTokenPayload:tokens.idTokenPayload} : idTokenInitialState);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return () => {
|
|
134
|
+
isMounted = false;
|
|
135
|
+
oidc.removeEventSubscription(newSubscriptionId);
|
|
136
|
+
};
|
|
137
|
+
}, [configurationName]);
|
|
138
|
+
return state;
|
|
139
|
+
}
|
package/src/oidc/User.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect, useState} from "react";
|
|
2
|
+
import Oidc from "./vanilla/oidc";
|
|
3
|
+
|
|
4
|
+
export enum OidcUserStatus {
|
|
5
|
+
Unauthenticated= 'Unauthenticated',
|
|
6
|
+
Loading = 'Loading user',
|
|
7
|
+
Loaded = 'User loaded',
|
|
8
|
+
LoadingError = 'Error loading user'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type OidcUser = {
|
|
12
|
+
user: any,
|
|
13
|
+
status: OidcUserStatus
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const useOidcUser = (configurationName="default") => {
|
|
17
|
+
const [oidcUser, setOidcUser] = useState<OidcUser>({user: null, status: OidcUserStatus.Unauthenticated});
|
|
18
|
+
|
|
19
|
+
const oidc = Oidc.get(configurationName);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
let isMounted = true;
|
|
22
|
+
|
|
23
|
+
if(oidc && oidc.tokens) {
|
|
24
|
+
setOidcUser({...oidcUser, status: OidcUserStatus.Loading});
|
|
25
|
+
oidc.userInfoAsync()
|
|
26
|
+
.then((info) => {
|
|
27
|
+
if (isMounted) {
|
|
28
|
+
setOidcUser({user: info, status: OidcUserStatus.Loaded});
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
.catch(() => setOidcUser({...oidcUser, status: OidcUserStatus.LoadingError}));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return () => { isMounted = false };
|
|
35
|
+
}, []);
|
|
36
|
+
|
|
37
|
+
return {oidcUser: oidcUser.user, oidcUserLoadingState: oidcUser.status}
|
|
38
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {ComponentType} from "react";
|
|
3
|
+
|
|
4
|
+
const AuthenticatingError: ComponentType<any> = () => (
|
|
5
|
+
<div className="oidc-authenticating">
|
|
6
|
+
<div className="oidc-authenticating__container">
|
|
7
|
+
<h1 className="oidc-authenticating__title">Error authentication</h1>
|
|
8
|
+
<p className="oidc-authenticating__content">An error occurred during authentication.</p>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export default AuthenticatingError;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {ComponentType} from "react";
|
|
3
|
+
|
|
4
|
+
const Authenticating : ComponentType<any> = () => (
|
|
5
|
+
<div className="oidc-authenticating">
|
|
6
|
+
<div className="oidc-authenticating__container">
|
|
7
|
+
<h1 className="oidc-authenticating__title">Authentication in progress</h1>
|
|
8
|
+
<p className="oidc-authenticating__content">You will be redirected to the login page.</p>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export default Authenticating;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, {useEffect, useState, ComponentType} from 'react';
|
|
2
|
+
import AuthenticatingError from "./AuthenticateError.component";
|
|
3
|
+
import Oidc from "../../vanilla/oidc";
|
|
4
|
+
import {getCustomHistory} from "../routes/withRouter";
|
|
5
|
+
|
|
6
|
+
export const CallBackSuccess: ComponentType<any> = () => (<div className="oidc-callback">
|
|
7
|
+
<div className="oidc-callback__container">
|
|
8
|
+
<h1 className="oidc-callback__title">Authentication complete</h1>
|
|
9
|
+
<p className="oidc-callback__content">You will be redirected to your application.</p>
|
|
10
|
+
</div>
|
|
11
|
+
</div>);
|
|
12
|
+
|
|
13
|
+
const CallbackManager: ComponentType<any> = ({callBackError, callBackSuccess, configurationName, withCustomHistory }) => {
|
|
14
|
+
|
|
15
|
+
const [error, setError] = useState(false);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
let isMounted = true;
|
|
18
|
+
const playCallbackAsync = async () => {
|
|
19
|
+
const getOidc = Oidc.get;
|
|
20
|
+
try {
|
|
21
|
+
const {callbackPath} = await getOidc(configurationName).loginCallbackWithAutoTokensRenewAsync();
|
|
22
|
+
const history = (withCustomHistory)? withCustomHistory(): getCustomHistory();
|
|
23
|
+
history.replaceState(callbackPath || "/")
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if(isMounted) {
|
|
26
|
+
setError(true);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
playCallbackAsync();
|
|
31
|
+
return () => {
|
|
32
|
+
isMounted = false;
|
|
33
|
+
};
|
|
34
|
+
},[]);
|
|
35
|
+
|
|
36
|
+
const CallbackErrorComponent = callBackError || AuthenticatingError;
|
|
37
|
+
const CallbackSuccessComponent = callBackSuccess || CallBackSuccess;
|
|
38
|
+
|
|
39
|
+
if(error){
|
|
40
|
+
return <CallbackErrorComponent configurationName={configurationName} />
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return <CallbackSuccessComponent configurationName={configurationName} />;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default CallbackManager;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {ComponentType} from "react";
|
|
3
|
+
|
|
4
|
+
const ServiceWorkerNotSupported : ComponentType<any> = () => (
|
|
5
|
+
<div className="oidc-serviceworker">
|
|
6
|
+
<div className="oidc-serviceworker__container">
|
|
7
|
+
<h1 className="oidc-serviceworker__title">Unable to authenticate on this browser</h1>
|
|
8
|
+
<p className="oidc-serviceworker__content">Your browser is not secure enough to make authentication work. Try updating your browser or use a newer browser.</p>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export default ServiceWorkerNotSupported;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React, {ComponentType} from 'react';
|
|
2
|
+
|
|
3
|
+
export const SessionLost: ComponentType<any> = () => (
|
|
4
|
+
<div className="oidc-session-lost">
|
|
5
|
+
<div className="oidc-session-lost__container">
|
|
6
|
+
<h1 className="oidc-session-lost__title">Session timed out</h1>
|
|
7
|
+
<p className="oidc-session-lost__content">
|
|
8
|
+
Your session has expired. Please re-authenticate.
|
|
9
|
+
</p>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export default SessionLost;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, {useEffect, ComponentType} from 'react';
|
|
2
|
+
import Oidc from "../../vanilla/oidc";
|
|
3
|
+
|
|
4
|
+
const CallbackManager: ComponentType<any> = ({configurationName }) => {
|
|
5
|
+
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
let isMounted = true;
|
|
8
|
+
const playCallbackAsync = async () => {
|
|
9
|
+
const getOidc = Oidc.get;
|
|
10
|
+
const oidc = getOidc(configurationName);
|
|
11
|
+
oidc.silentLoginCallBackAsync();
|
|
12
|
+
};
|
|
13
|
+
playCallbackAsync();
|
|
14
|
+
return () => {
|
|
15
|
+
isMounted = false;
|
|
16
|
+
};
|
|
17
|
+
},[]);
|
|
18
|
+
|
|
19
|
+
return <></>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default CallbackManager;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, {useEffect, ComponentType} from 'react';
|
|
2
|
+
import Oidc from "../../vanilla/oidc";
|
|
3
|
+
import {getParseQueryStringFromLocation} from "../../vanilla/route-utils";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const SilentLogin: ComponentType<any> = (({configurationName }) => {
|
|
7
|
+
const queryParams = getParseQueryStringFromLocation(window.location.href);
|
|
8
|
+
|
|
9
|
+
const getOidc = Oidc.get;
|
|
10
|
+
const oidc = getOidc(configurationName);
|
|
11
|
+
|
|
12
|
+
let extras = null;
|
|
13
|
+
|
|
14
|
+
for (let [key, value] of Object.entries(queryParams)) {
|
|
15
|
+
if(key === "state" || key == "scope"){
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if(extras === null){
|
|
19
|
+
extras = {};
|
|
20
|
+
}
|
|
21
|
+
extras[key] = value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if(!oidc.tokens){
|
|
26
|
+
oidc.loginAsync(null, extras, true, queryParams.scope);
|
|
27
|
+
}
|
|
28
|
+
return () => {
|
|
29
|
+
}
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
return <></>;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default SilentLogin;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as Authenticating } from './Authenticating.component';
|
|
2
|
+
export { default as Callback, CallBackSuccess } from './Callback.component';
|
|
3
|
+
export { default as SessionLost } from './SessionLost.component';
|
|
4
|
+
export { default as Loading } from './Loading.component';
|
|
5
|
+
export { default as AuthenticateError } from './AuthenticateError.component';
|
|
6
|
+
export { default as ServiceWorkerNotSupported } from './ServiceWorkerNotSupported.component';
|