@axa-fr/react-oidc 6.0.0-alpha9 → 6.0.0-beta0
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/vanilla/oidc.d.ts.map +1 -1
- package/dist/vanilla/oidc.js +124 -104
- package/dist/vanilla/oidc.js.map +1 -1
- package/package.json +2 -2
- package/src/oidc/vanilla/oidc.ts +71 -75
- package/src/App.css +0 -38
- package/src/App.specold.tsx +0 -46
- package/src/App.tsx +0 -96
- package/src/FetchUser.tsx +0 -53
- package/src/Home.tsx +0 -22
- package/src/MultiAuth.tsx +0 -116
- package/src/Profile.tsx +0 -77
- package/src/configurations.ts +0 -70
- package/src/index.css +0 -13
- package/src/index.tsx +0 -9
- package/src/logo.svg +0 -7
- package/src/override/AuthenticateError.component.tsx +0 -14
- package/src/override/Authenticating.component.tsx +0 -14
- package/src/override/Callback.component.tsx +0 -13
- package/src/override/Loading.component.tsx +0 -13
- package/src/override/ServiceWorkerNotSupported.component.tsx +0 -15
- package/src/override/SessionLost.component.tsx +0 -21
- package/src/override/style.ts +0 -10
- package/src/setupTests.js +0 -5
package/src/oidc/vanilla/oidc.ts
CHANGED
|
@@ -20,6 +20,45 @@ import {CheckSessionIFrame} from "./checkSessionIFrame"
|
|
|
20
20
|
import {getParseQueryStringFromLocation} from "./route-utils";
|
|
21
21
|
import {AuthorizationServiceConfigurationJson} from "@openid/appauth/src/authorization_service_configuration";
|
|
22
22
|
|
|
23
|
+
const performTokenRequestAsync= async (url, details, extras) => {
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
for (let [key, value] of Object.entries(extras)) {
|
|
27
|
+
if (details[key] === undefined) {
|
|
28
|
+
details[key] = value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let formBody = [];
|
|
33
|
+
for (const property in details) {
|
|
34
|
+
const encodedKey = encodeURIComponent(property);
|
|
35
|
+
const encodedValue = encodeURIComponent(details[property]);
|
|
36
|
+
formBody.push(`${encodedKey}=${encodedValue}`);
|
|
37
|
+
}
|
|
38
|
+
const formBodyString = formBody.join("&");
|
|
39
|
+
|
|
40
|
+
const response = await internalFetch(url, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
headers: {
|
|
43
|
+
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
|
44
|
+
},
|
|
45
|
+
body: formBodyString,
|
|
46
|
+
});
|
|
47
|
+
if(response.status !== 200){
|
|
48
|
+
return {success:false, status: response.status}
|
|
49
|
+
}
|
|
50
|
+
const result = await response.json();
|
|
51
|
+
return { success : true,
|
|
52
|
+
data : {
|
|
53
|
+
accessToken: result.access_token,
|
|
54
|
+
expiresIn: result.expires_in,
|
|
55
|
+
idToken: result.id_token,
|
|
56
|
+
refreshToken: result.refresh_token,
|
|
57
|
+
scope: result.scope,
|
|
58
|
+
tokenType: result.token_type,
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
23
62
|
|
|
24
63
|
const internalFetch = async (url, headers, numberRetry=0) => {
|
|
25
64
|
let response;
|
|
@@ -30,7 +69,7 @@ const internalFetch = async (url, headers, numberRetry=0) => {
|
|
|
30
69
|
() => reject(new Error('Timeout')), 10000))]);
|
|
31
70
|
} catch (e) {
|
|
32
71
|
if (e.message === 'Timeout'
|
|
33
|
-
|| e.message === 'Network request failed'
|
|
72
|
+
|| e.message === 'Network request failed') {
|
|
34
73
|
if(numberRetry <=2) {
|
|
35
74
|
return await internalFetch(url, headers, numberRetry + 1);
|
|
36
75
|
}
|
|
@@ -378,13 +417,13 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
378
417
|
static eventNames = eventNames;
|
|
379
418
|
|
|
380
419
|
silentSigninCallbackFromIFrame(){
|
|
381
|
-
if (this.configuration.silent_redirect_uri) {
|
|
420
|
+
if (this.configuration.silent_redirect_uri && this.configuration.silent_signin_uri) {
|
|
382
421
|
const queryParams = getParseQueryStringFromLocation(window.location.href);
|
|
383
422
|
window.top.postMessage(`${this.configurationName}_oidc_tokens:${JSON.stringify({tokens:this.tokens, sessionState:queryParams.session_state})}`, window.location.origin);
|
|
384
423
|
}
|
|
385
424
|
}
|
|
386
425
|
silentSigninErrorCallbackFromIFrame(){
|
|
387
|
-
if (this.configuration.silent_redirect_uri) {
|
|
426
|
+
if (this.configuration.silent_redirect_uri && this.configuration.silent_signin_uri) {
|
|
388
427
|
const queryParams = getParseQueryStringFromLocation(window.location.href);
|
|
389
428
|
window.top.postMessage(`${this.configurationName}_oidc_error:${JSON.stringify({error:queryParams.error})}`, window.location.origin);
|
|
390
429
|
}
|
|
@@ -871,13 +910,8 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
871
910
|
}
|
|
872
911
|
|
|
873
912
|
async refreshTokensAsync(refreshToken) {
|
|
874
|
-
|
|
875
|
-
/*while (document.hidden) {
|
|
876
|
-
await sleepAsync(1000);
|
|
877
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message:"wait because document is hidden"});
|
|
878
|
-
}*/
|
|
879
913
|
|
|
880
|
-
const localSilentSigninAsync= async (
|
|
914
|
+
const localSilentSigninAsync= async () => {
|
|
881
915
|
try {
|
|
882
916
|
const silent_token_response = await this.silentSigninAsync();
|
|
883
917
|
if (silent_token_response) {
|
|
@@ -890,13 +924,10 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
890
924
|
timer.clearTimeout(this.timeoutId);
|
|
891
925
|
this.timeoutId=null;
|
|
892
926
|
}
|
|
893
|
-
this.publishEvent(eventNames.refreshTokensAsync_error,
|
|
927
|
+
this.publishEvent(eventNames.refreshTokensAsync_error, {message: "refresh token and silent refresh failed"});
|
|
894
928
|
return null;
|
|
895
929
|
}
|
|
896
|
-
|
|
897
|
-
try{
|
|
898
|
-
this.publishEvent(eventNames.refreshTokensAsync_begin, {refreshToken:refreshToken});
|
|
899
|
-
|
|
930
|
+
|
|
900
931
|
const configuration = this.configuration;
|
|
901
932
|
const clientId = configuration.client_id;
|
|
902
933
|
const redirectUri = configuration.redirect_uri;
|
|
@@ -907,7 +938,6 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
907
938
|
return await localSilentSigninAsync();
|
|
908
939
|
}
|
|
909
940
|
|
|
910
|
-
|
|
911
941
|
let extras = {};
|
|
912
942
|
if(configuration.token_request_extras) {
|
|
913
943
|
for (let [key, value] of Object.entries(configuration.token_request_extras)) {
|
|
@@ -915,73 +945,39 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
915
945
|
}
|
|
916
946
|
}
|
|
917
947
|
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
// use the token response to make a request for an access token
|
|
921
|
-
const request = new TokenRequest({
|
|
948
|
+
|
|
949
|
+
const details = {
|
|
922
950
|
client_id: clientId,
|
|
923
951
|
redirect_uri: redirectUri,
|
|
924
952
|
grant_type: GRANT_TYPE_REFRESH_TOKEN,
|
|
925
|
-
code: undefined,
|
|
926
953
|
refresh_token: refreshToken,
|
|
927
|
-
|
|
928
|
-
});
|
|
954
|
+
};
|
|
929
955
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
};
|
|
940
|
-
|
|
941
|
-
for (let [key, value] of Object.entries(extras)) {
|
|
942
|
-
if (details[key] === undefined) {
|
|
943
|
-
details[key] = value;
|
|
956
|
+
let index = 0;
|
|
957
|
+
while (index <=2) {
|
|
958
|
+
try {
|
|
959
|
+
this.publishEvent(eventNames.refreshTokensAsync_begin, {refreshToken:refreshToken, tryNumber: index});
|
|
960
|
+
if(index > 1) {
|
|
961
|
+
while (document.hidden) {
|
|
962
|
+
await sleepAsync(1000);
|
|
963
|
+
this.publishEvent(eventNames.refreshTokensAsync, {message: "wait because document is hidden"});
|
|
964
|
+
}
|
|
944
965
|
}
|
|
966
|
+
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
|
|
967
|
+
if (tokenResponse.success) {
|
|
968
|
+
this.publishEvent(eventNames.refreshTokensAsync_end, {success: tokenResponse.success});
|
|
969
|
+
return tokenResponse.data;
|
|
970
|
+
} else {
|
|
971
|
+
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "bad request" , tokenResponse: tokenResponse});
|
|
972
|
+
return await localSilentSigninAsync();
|
|
973
|
+
}
|
|
974
|
+
} catch (exception) {
|
|
975
|
+
console.error(exception);
|
|
976
|
+
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "exception" ,exception: exception});
|
|
945
977
|
}
|
|
946
|
-
|
|
947
|
-
let formBody = [];
|
|
948
|
-
for (const property in details) {
|
|
949
|
-
const encodedKey = encodeURIComponent(property);
|
|
950
|
-
const encodedValue = encodeURIComponent(details[property]);
|
|
951
|
-
formBody.push(`${encodedKey}=${encodedValue}`);
|
|
952
|
-
}
|
|
953
|
-
const formBodyString = formBody.join("&");
|
|
954
|
-
|
|
955
|
-
const response = await internalFetch(url, {
|
|
956
|
-
method: 'POST',
|
|
957
|
-
headers: {
|
|
958
|
-
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
|
959
|
-
},
|
|
960
|
-
body: formBodyString,
|
|
961
|
-
});
|
|
962
|
-
if(response.status >= 299){
|
|
963
|
-
throw new Error("Error refreshing token");
|
|
964
|
-
}
|
|
965
|
-
const result = await response.json();
|
|
966
|
-
return {
|
|
967
|
-
accessToken: result.access_token,
|
|
968
|
-
expiresIn: result.expires_in,
|
|
969
|
-
idToken: result.id_token,
|
|
970
|
-
refreshToken: result.refresh_token,
|
|
971
|
-
scope: result.scope,
|
|
972
|
-
tokenType: result.token_type,
|
|
973
|
-
};
|
|
978
|
+
index++;
|
|
974
979
|
}
|
|
975
|
-
|
|
976
|
-
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint)
|
|
977
|
-
|
|
978
|
-
this.publishEvent(eventNames.refreshTokensAsync_end, {message:"success"});
|
|
979
|
-
return tokenResponse;
|
|
980
|
-
} catch(exception) {
|
|
981
|
-
console.error(exception);
|
|
982
|
-
this.publishEvent(eventNames.refreshTokensAsync_silent_error, exception);
|
|
983
|
-
return await localSilentSigninAsync(exception);
|
|
984
|
-
}
|
|
980
|
+
|
|
985
981
|
}
|
|
986
982
|
|
|
987
983
|
syncTokensAsyncPromise=null;
|
|
@@ -1008,7 +1004,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
1008
1004
|
if (silent_token_response && silent_token_response.tokens) {
|
|
1009
1005
|
this.tokens = await setTokensAsync(serviceWorker, silent_token_response.tokens);
|
|
1010
1006
|
} else{
|
|
1011
|
-
this.publishEvent(eventNames.syncTokensAsync_error,
|
|
1007
|
+
this.publishEvent(eventNames.syncTokensAsync_error, {message:"no token found in result"});
|
|
1012
1008
|
if(this.timeoutId){
|
|
1013
1009
|
timer.clearTimeout(this.timeoutId);
|
|
1014
1010
|
this.timeoutId=null;
|
package/src/App.css
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
.App {
|
|
2
|
-
text-align: center;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
.App-logo {
|
|
6
|
-
height: 40vmin;
|
|
7
|
-
pointer-events: none;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
11
|
-
.App-logo {
|
|
12
|
-
animation: App-logo-spin infinite 20s linear;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.App-header {
|
|
17
|
-
background-color: #282c34;
|
|
18
|
-
min-height: 100vh;
|
|
19
|
-
display: flex;
|
|
20
|
-
flex-direction: column;
|
|
21
|
-
align-items: center;
|
|
22
|
-
justify-content: center;
|
|
23
|
-
font-size: calc(10px + 2vmin);
|
|
24
|
-
color: white;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.App-link {
|
|
28
|
-
color: #61dafb;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@keyframes App-logo-spin {
|
|
32
|
-
from {
|
|
33
|
-
transform: rotate(0deg);
|
|
34
|
-
}
|
|
35
|
-
to {
|
|
36
|
-
transform: rotate(360deg);
|
|
37
|
-
}
|
|
38
|
-
}
|
package/src/App.specold.tsx
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// __tests__/fetch.test.js
|
|
2
|
-
/*import React from 'react'
|
|
3
|
-
import {rest} from 'msw'
|
|
4
|
-
import {setupServer} from 'msw/node'
|
|
5
|
-
import {render, fireEvent, waitFor, screen} from '@testing-library/react'
|
|
6
|
-
import '@testing-library/jest-dom'
|
|
7
|
-
import App from "./App";
|
|
8
|
-
import {act} from "react-dom/test-utils";
|
|
9
|
-
|
|
10
|
-
const server = setupServer(
|
|
11
|
-
rest.get('http://api/.well-known/openid-configuration', (req, res, ctx) => {
|
|
12
|
-
return res( ctx.status(200),ctx.json({
|
|
13
|
-
"issuer":"https://demo.identityserver.io",
|
|
14
|
-
"jwks_uri":"https://demo.identityserver.io/.well-known/openid-configuration/jwks",
|
|
15
|
-
"authorization_endpoint":"https://demo.identityserver.io/connect/authorize",
|
|
16
|
-
"token_endpoint":"https://demo.identityserver.io/connect/token",
|
|
17
|
-
"userinfo_endpoint":"https://demo.identityserver.io/connect/userinfo",
|
|
18
|
-
"end_session_endpoint":"https://demo.identityserver.io/connect/endsession",
|
|
19
|
-
"check_session_iframe":"https://demo.identityserver.io/connect/checksession",
|
|
20
|
-
"revocation_endpoint":"https://demo.identityserver.io/connect/revocation",
|
|
21
|
-
"introspection_endpoint":"https://demo.identityserver.io/connect/introspect",
|
|
22
|
-
"device_authorization_endpoint":"https://demo.identityserver.io/connect/deviceauthorization","frontchannel_logout_supported":true,"frontchannel_logout_session_supported":true,"backchannel_logout_supported":true,"backchannel_logout_session_supported":true,"scopes_supported":["openid","profile","email","api","api.scope1","api.scope2","scope2","policyserver.runtime","policyserver.management","offline_access"],"claims_supported":["sub","name","family_name","given_name","middle_name","nickname","preferred_username","profile","picture","website","gender","birthdate","zoneinfo","locale","updated_at","email","email_verified"],"grant_types_supported":["authorization_code","client_credentials","refresh_token","implicit","password","urn:ietf:params:oauth:grant-type:device_code"],"response_types_supported":["code","token","id_token","id_token token","code id_token","code token","code id_token token"],"response_modes_supported":["form_post","query","fragment"],"token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post"],"id_token_signing_alg_values_supported":["RS256"],"subject_types_supported":["public"],"code_challenge_methods_supported":["plain","S256"],"request_parameter_supported":true}))
|
|
23
|
-
}),
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
beforeAll(() => server.listen())
|
|
27
|
-
afterEach(() => server.resetHandlers())
|
|
28
|
-
afterAll(() => server.close())
|
|
29
|
-
|
|
30
|
-
test('Load home page then login should log', async () => {
|
|
31
|
-
|
|
32
|
-
const configuration = {
|
|
33
|
-
client_id: 'interactive.public.short',
|
|
34
|
-
redirect_uri: 'http://localhost:4200/authentication/callback',
|
|
35
|
-
scope: 'openid profile email api offline_access',
|
|
36
|
-
authority: 'http://api',
|
|
37
|
-
refresh_time_before_tokens_expiration_in_second: 70,
|
|
38
|
-
};
|
|
39
|
-
// @ts-ignore
|
|
40
|
-
const {debug, getByText, rerender} = render(<App configuration={configuration}/>);
|
|
41
|
-
await waitFor(() => getByText('React Demo Application protected by OpenId Connect'));
|
|
42
|
-
fireEvent.click(screen.getByText('Login'));
|
|
43
|
-
await waitFor(() => getByText('Authentification en cours'));
|
|
44
|
-
|
|
45
|
-
})
|
|
46
|
-
*/
|
package/src/App.tsx
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import React, {useReducer} from 'react';
|
|
2
|
-
import {BrowserRouter, Route, Link, Routes} from 'react-router-dom';
|
|
3
|
-
import { Home } from "./Home";
|
|
4
|
-
import { Profile, SecureProfile } from "./Profile";
|
|
5
|
-
import { configurationAuth0, configurationIdentityServer, configurationIdentityServerWithoutDiscovery } from './configurations';
|
|
6
|
-
import { withOidcSecure, OidcProvider } from "./oidc";
|
|
7
|
-
import {FetchUserHoc, FetchUserHook} from "./FetchUser";
|
|
8
|
-
import { MultiAuthContainer } from "./MultiAuth";
|
|
9
|
-
|
|
10
|
-
const OidcSecureHoc = withOidcSecure(Profile);
|
|
11
|
-
|
|
12
|
-
function reducer(state, action) {
|
|
13
|
-
switch (action.type) {
|
|
14
|
-
case 'event':
|
|
15
|
-
return [{...action.data, date:Date.now()}, ...state]
|
|
16
|
-
default:
|
|
17
|
-
throw new Error();
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function App() {
|
|
22
|
-
const [show, setShow] = React.useState(false);
|
|
23
|
-
const [events, dispatch] = useReducer(reducer, []);
|
|
24
|
-
|
|
25
|
-
const onEvent=(configurationName, eventName, data )=>{
|
|
26
|
-
// console.log(`oidc:${configurationName}:${eventName}`, data);
|
|
27
|
-
dispatch({type: 'event', data: {name: `oidc:${configurationName}:${eventName}`, data}})
|
|
28
|
-
}
|
|
29
|
-
return (<>
|
|
30
|
-
|
|
31
|
-
<OidcProvider configuration={configurationIdentityServer} onEvent={onEvent}>
|
|
32
|
-
<BrowserRouter>
|
|
33
|
-
<nav className="navbar navbar-expand-lg navbar-dark bg-primary">
|
|
34
|
-
<a className="navbar-brand" href="/">@axa-fr/react-oidc</a>
|
|
35
|
-
<button className="navbar-toggler" type="button" onClick={() => setShow(!show)} data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
|
36
|
-
<span className="navbar-toggler-icon"/>
|
|
37
|
-
</button>
|
|
38
|
-
<div style={show ? { display: "block" } : { display: 'none' }} className="collapse navbar-collapse" id="navbarNav">
|
|
39
|
-
<ul className="navbar-nav">
|
|
40
|
-
<li className="nav-item">
|
|
41
|
-
<Link className="nav-link" to="/">Home</Link>
|
|
42
|
-
</li>
|
|
43
|
-
<li className="nav-item">
|
|
44
|
-
<Link className="nav-link" to="/profile">Profile</Link>
|
|
45
|
-
</li>
|
|
46
|
-
<li className="nav-item">
|
|
47
|
-
<Link className="nav-link" to="/profile-secure-component">Secure Profile Component</Link>
|
|
48
|
-
</li>
|
|
49
|
-
<li className="nav-item">
|
|
50
|
-
<Link className="nav-link" to="/profile-secure-hoc">Secure Profile Hoc</Link>
|
|
51
|
-
</li>
|
|
52
|
-
<li className="nav-item">
|
|
53
|
-
<Link className="nav-link" to="/user-fetch-secure-hoc">Secure User Fetch Hoc</Link>
|
|
54
|
-
</li>
|
|
55
|
-
<li className="nav-item">
|
|
56
|
-
<Link className="nav-link" to="/user-fetch-secure-hook">Secure User Fetch Hook</Link>
|
|
57
|
-
</li>
|
|
58
|
-
<li className="nav-item">
|
|
59
|
-
<Link className="nav-link" to="/multi-auth">Multi Auth</Link>
|
|
60
|
-
</li>
|
|
61
|
-
</ul>
|
|
62
|
-
</div>
|
|
63
|
-
</nav>
|
|
64
|
-
|
|
65
|
-
<div>
|
|
66
|
-
<Routes>
|
|
67
|
-
<Route path="/" element={<Home></Home>} />
|
|
68
|
-
<Route path="/profile" element={<Profile></Profile>} />
|
|
69
|
-
<Route path="/profile-secure-component" element={<SecureProfile></SecureProfile>} />
|
|
70
|
-
<Route path="/profile-secure-hoc" element={<OidcSecureHoc></OidcSecureHoc>} />
|
|
71
|
-
<Route path="/user-fetch-secure-hoc" element={<FetchUserHoc></FetchUserHoc>} />
|
|
72
|
-
<Route path="/user-fetch-secure-hook" element={<FetchUserHook></FetchUserHook>} />
|
|
73
|
-
<Route path="/multi-auth/*" element={<MultiAuthContainer></MultiAuthContainer>} />
|
|
74
|
-
</Routes>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
</BrowserRouter>
|
|
78
|
-
</OidcProvider>
|
|
79
|
-
<div className="container-fluid mt-3">
|
|
80
|
-
<div className="card">
|
|
81
|
-
<div className="card-body" >
|
|
82
|
-
<h5 className="card-title">Default configuration Events</h5>
|
|
83
|
-
<div style={{"overflowX": "hidden", "overflowY": "scroll", "maxHeight": "400px"}}>
|
|
84
|
-
{events.map(e => {
|
|
85
|
-
const date = new Date(e.date);
|
|
86
|
-
const dateFormated = `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
|
|
87
|
-
return <p>{dateFormated} {e.name}: { JSON.stringify(e.data)}</p>
|
|
88
|
-
})}
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
</div></>
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export default App;
|
package/src/FetchUser.tsx
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import React, {useEffect, useState} from 'react';
|
|
2
|
-
|
|
3
|
-
import {useOidcFetch, withOidcFetch} from "./oidc/FetchToken";
|
|
4
|
-
import {OidcSecure} from "./oidc";
|
|
5
|
-
|
|
6
|
-
const DisplayUserInfo = ({ fetch }) => {
|
|
7
|
-
const [oidcUser, setOidcUser] = useState(null);
|
|
8
|
-
const [isLoading, setLoading] = useState(true);
|
|
9
|
-
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
const fetchUserInfoAsync = async () => {
|
|
12
|
-
const res = await fetch("https://demo.duendesoftware.com/connect/userinfo");
|
|
13
|
-
if (res.status != 200) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
return res.json();
|
|
17
|
-
};
|
|
18
|
-
let isMounted = true;
|
|
19
|
-
fetchUserInfoAsync().then((userInfo) => {
|
|
20
|
-
if(isMounted) {
|
|
21
|
-
setLoading(false);
|
|
22
|
-
setOidcUser(userInfo)
|
|
23
|
-
}
|
|
24
|
-
})
|
|
25
|
-
return () => {
|
|
26
|
-
isMounted = false;
|
|
27
|
-
};
|
|
28
|
-
},[]);
|
|
29
|
-
|
|
30
|
-
if(isLoading){
|
|
31
|
-
return <>Loading</>;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<div className="container mt-3">
|
|
36
|
-
<div className="card text-white bg-success mb-3">
|
|
37
|
-
<div className="card-body">
|
|
38
|
-
<h5 className="card-title">User information</h5>
|
|
39
|
-
{oidcUser != null && <p className="card-text">{JSON.stringify(oidcUser)}</p>}
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
)
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const UserInfoWithFetchHoc = withOidcFetch(fetch)(DisplayUserInfo);
|
|
47
|
-
|
|
48
|
-
export const FetchUserHoc= () => <OidcSecure><UserInfoWithFetchHoc/></OidcSecure>;
|
|
49
|
-
|
|
50
|
-
export const FetchUserHook= () => {
|
|
51
|
-
const {fetch} = useOidcFetch();
|
|
52
|
-
return <OidcSecure><DisplayUserInfo fetch={fetch} /></OidcSecure>
|
|
53
|
-
}
|
package/src/Home.tsx
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import {useOidc} from "./oidc";
|
|
3
|
-
|
|
4
|
-
export const Home = () => {
|
|
5
|
-
|
|
6
|
-
const { login, logout, isAuthenticated} = useOidc();
|
|
7
|
-
|
|
8
|
-
return (
|
|
9
|
-
<div className="container-fluid mt-3">
|
|
10
|
-
<div className="card">
|
|
11
|
-
<div className="card-body">
|
|
12
|
-
<h5 className="card-title">Home</h5>
|
|
13
|
-
<p className="card-text">React Demo Application protected by OpenId Connect. More info on about oidc on <a href="https://github.com/AxaGuilDEv/react-oidc">GitHub @axa-fr/react-oidc</a></p>
|
|
14
|
-
{!isAuthenticated && <p><button type="button" className="btn btn-primary" onClick={() => login('/profile')}>Login</button></p>}
|
|
15
|
-
{!isAuthenticated && <p><button type="button" className="btn btn-primary" onClick={() => login('/profile', null, "youhou")}>Login with state</button></p>}
|
|
16
|
-
{isAuthenticated && <p><button type="button" className="btn btn-primary" onClick={() => logout('/profile')}>logout /profile</button></p>}
|
|
17
|
-
{isAuthenticated && <p><button type="button" className="btn btn-primary" onClick={() => logout('')}>logout</button></p>}
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
)
|
|
22
|
-
};
|
package/src/MultiAuth.tsx
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import React, {useState} from 'react';
|
|
2
|
-
import {OidcProvider, useOidc, useOidcAccessToken, useOidcIdToken} from "./oidc";
|
|
3
|
-
import { configurationIdentityServer, configurationIdentityServerWithHash, configurationGoogle} from "./configurations";
|
|
4
|
-
import AuthenticatingError from "./override/AuthenticateError.component"
|
|
5
|
-
import Authenticating from "./override/Authenticating.component"
|
|
6
|
-
import Loading from "./override/Loading.component"
|
|
7
|
-
import {CallBackSuccess} from "./override/Callback.component"
|
|
8
|
-
import SessionLost from "./override/SessionLost.component"
|
|
9
|
-
import ServiceWorkerNotSupported from "./override/ServiceWorkerNotSupported.component"
|
|
10
|
-
|
|
11
|
-
const MultiAuth = ( {configurationName, handleConfigurationChange }) => {
|
|
12
|
-
const { login, logout, isAuthenticated} = useOidc(configurationName);
|
|
13
|
-
const [fname, setFname] = useState("")
|
|
14
|
-
|
|
15
|
-
const handleChange = e => {
|
|
16
|
-
setFname(e.target.value)
|
|
17
|
-
}
|
|
18
|
-
return (
|
|
19
|
-
<div className="container-fluid mt-3">
|
|
20
|
-
<div className="card">
|
|
21
|
-
<div className="card-body">
|
|
22
|
-
<h5 className="card-title">Multiple Authentication</h5>
|
|
23
|
-
<form>
|
|
24
|
-
<label>
|
|
25
|
-
First Name:{" "}
|
|
26
|
-
<input type="text" value={fname} onChange={handleChange} />
|
|
27
|
-
</label>
|
|
28
|
-
</form>
|
|
29
|
-
<p className="card-text">React Demo Application protected by OpenId Connect with MultipleAuthentication.
|
|
30
|
-
<br/>For example, config_1 can have other sensitive scope, config_2 does not ask for the "offline_access" so it does not retrieve the most sensitive token "refresh_token" for very sensitive operation, it retrive only access_token valid for a small amout of time.</p>
|
|
31
|
-
<select value={configurationName} onChange={handleConfigurationChange} >
|
|
32
|
-
<option value="config_classic">config_classic</option>
|
|
33
|
-
<option value="config_without_refresh_token">config_without_refresh_token</option>
|
|
34
|
-
<option value="config_google">google</option>
|
|
35
|
-
<option value="config_with_hash">config_with_hash</option>
|
|
36
|
-
</select>
|
|
37
|
-
{!isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => login()}>Login</button>}
|
|
38
|
-
{isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => logout()}>logout</button>}
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
if(!sessionStorage.configurationName){
|
|
46
|
-
sessionStorage.configurationName = "config_classic";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const MultiAuthContainer = () => {
|
|
50
|
-
const [isSessionLost, setIsSessionLost] = useState(false)
|
|
51
|
-
const [configurationName, setConfigurationName] = useState(sessionStorage.configurationName);
|
|
52
|
-
const callBack = window.location.origin+"/multi-auth/authentification/callback2";
|
|
53
|
-
const silent_redirect_uri = window.location.origin+"/multi-auth/authentification/silent-callback2";
|
|
54
|
-
const configurations = {
|
|
55
|
-
config_classic: {...configurationIdentityServer,
|
|
56
|
-
redirect_uri:callBack,
|
|
57
|
-
silent_redirect_uri,
|
|
58
|
-
scope: 'openid profile email api offline_access'
|
|
59
|
-
},
|
|
60
|
-
config_without_refresh_token: {...configurationIdentityServer,
|
|
61
|
-
redirect_uri:callBack,
|
|
62
|
-
silent_redirect_uri: "",
|
|
63
|
-
scope: 'openid profile email api'},
|
|
64
|
-
config_google: { ...configurationGoogle },
|
|
65
|
-
config_with_hash: { ...configurationIdentityServerWithHash}
|
|
66
|
-
}
|
|
67
|
-
const handleConfigurationChange = (event) => {
|
|
68
|
-
const configurationName = event.target.value;
|
|
69
|
-
sessionStorage.configurationName = configurationName;
|
|
70
|
-
setConfigurationName(configurationName);
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const onSessionLost = ()=>{
|
|
75
|
-
setIsSessionLost(true);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return (
|
|
79
|
-
<>
|
|
80
|
-
<OidcProvider configuration={configurations[configurationName]}
|
|
81
|
-
configurationName={configurationName}
|
|
82
|
-
loadingComponent={Loading}
|
|
83
|
-
authenticatingErrorComponent={AuthenticatingError}
|
|
84
|
-
authenticatingComponent={Authenticating}
|
|
85
|
-
serviceWorkerNotSupportedComponent={ServiceWorkerNotSupported}
|
|
86
|
-
callbackSuccessComponent={CallBackSuccess}
|
|
87
|
-
onSessionLost={onSessionLost}
|
|
88
|
-
>
|
|
89
|
-
{ isSessionLost && <SessionLost configurationName={configurationName}/>}
|
|
90
|
-
<MultiAuth configurationName={configurationName} handleConfigurationChange={handleConfigurationChange} />
|
|
91
|
-
<DisplayAccessToken configurationName={configurationName} />
|
|
92
|
-
</OidcProvider>
|
|
93
|
-
</>
|
|
94
|
-
);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const DisplayAccessToken = ({configurationName}) => {
|
|
98
|
-
const{ accessToken, accessTokenPayload } = useOidcAccessToken(configurationName);
|
|
99
|
-
const{ idTokenPayload } = useOidcIdToken(configurationName);
|
|
100
|
-
|
|
101
|
-
if(!accessToken){
|
|
102
|
-
return <p>you are not authentified</p>
|
|
103
|
-
}
|
|
104
|
-
return (
|
|
105
|
-
<div className="card text-white bg-info mb-3">
|
|
106
|
-
<div className="card-body">
|
|
107
|
-
<h5 className="card-title">Access Token</h5>
|
|
108
|
-
<p style={{color:'red', "backgroundColor": 'white'}}>Please consider to configure the ServiceWorker in order to protect your application from XSRF attacks. "access_token" and "refresh_token" will never be accessible from your client side javascript.</p>
|
|
109
|
-
{<p className="card-text">Access Token: {JSON.stringify(accessToken)}</p>}
|
|
110
|
-
{accessTokenPayload != null && <p className="card-text">Access Token Payload: {JSON.stringify(accessTokenPayload)}</p>}
|
|
111
|
-
<h5 className="card-title">Id Token</h5>
|
|
112
|
-
{idTokenPayload != null && <p className="card-text">Access Token Payload: {JSON.stringify(idTokenPayload)}</p>}
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
)
|
|
116
|
-
};
|