@axa-fr/react-oidc 5.7.0-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.
Files changed (160) hide show
  1. package/README.md +502 -0
  2. package/dist/FetchToken.d.ts +10 -0
  3. package/dist/FetchToken.d.ts.map +1 -0
  4. package/dist/FetchToken.js +107 -0
  5. package/dist/FetchToken.js.map +1 -0
  6. package/dist/OidcProvider.d.ts +25 -0
  7. package/dist/OidcProvider.d.ts.map +1 -0
  8. package/dist/OidcProvider.js +133 -0
  9. package/dist/OidcProvider.js.map +1 -0
  10. package/dist/OidcSecure.d.ts +10 -0
  11. package/dist/OidcSecure.d.ts.map +1 -0
  12. package/dist/OidcSecure.js +68 -0
  13. package/dist/OidcSecure.js.map +1 -0
  14. package/dist/OidcServiceWorker.js +272 -0
  15. package/dist/OidcTrustedDomains.js +6 -0
  16. package/dist/ReactOidc.d.ts +17 -0
  17. package/dist/ReactOidc.d.ts.map +1 -0
  18. package/dist/ReactOidc.js +106 -0
  19. package/dist/ReactOidc.js.map +1 -0
  20. package/dist/User.d.ts +15 -0
  21. package/dist/User.d.ts.map +1 -0
  22. package/dist/User.js +48 -0
  23. package/dist/User.js.map +1 -0
  24. package/dist/core/default-component/AuthenticateError.component.d.ts +4 -0
  25. package/dist/core/default-component/AuthenticateError.component.d.ts.map +1 -0
  26. package/dist/core/default-component/AuthenticateError.component.js +32 -0
  27. package/dist/core/default-component/AuthenticateError.component.js.map +1 -0
  28. package/dist/core/default-component/Authenticating.component.d.ts +4 -0
  29. package/dist/core/default-component/Authenticating.component.d.ts.map +1 -0
  30. package/dist/core/default-component/Authenticating.component.js +32 -0
  31. package/dist/core/default-component/Authenticating.component.js.map +1 -0
  32. package/dist/core/default-component/Callback.component.d.ts +5 -0
  33. package/dist/core/default-component/Callback.component.d.ts.map +1 -0
  34. package/dist/core/default-component/Callback.component.js +118 -0
  35. package/dist/core/default-component/Callback.component.js.map +1 -0
  36. package/dist/core/default-component/Loading.component.d.ts +4 -0
  37. package/dist/core/default-component/Loading.component.d.ts.map +1 -0
  38. package/dist/core/default-component/Loading.component.js +29 -0
  39. package/dist/core/default-component/Loading.component.js.map +1 -0
  40. package/dist/core/default-component/ServiceWorkerInstall.component.d.ts +4 -0
  41. package/dist/core/default-component/ServiceWorkerInstall.component.d.ts.map +1 -0
  42. package/dist/core/default-component/ServiceWorkerInstall.component.js +122 -0
  43. package/dist/core/default-component/ServiceWorkerInstall.component.js.map +1 -0
  44. package/dist/core/default-component/ServiceWorkerNotSupported.component.d.ts +4 -0
  45. package/dist/core/default-component/ServiceWorkerNotSupported.component.d.ts.map +1 -0
  46. package/dist/core/default-component/ServiceWorkerNotSupported.component.js +32 -0
  47. package/dist/core/default-component/ServiceWorkerNotSupported.component.js.map +1 -0
  48. package/dist/core/default-component/SessionLost.component.d.ts +4 -0
  49. package/dist/core/default-component/SessionLost.component.d.ts.map +1 -0
  50. package/dist/core/default-component/SessionLost.component.js +14 -0
  51. package/dist/core/default-component/SessionLost.component.js.map +1 -0
  52. package/dist/core/default-component/SilentCallback.component.d.ts +4 -0
  53. package/dist/core/default-component/SilentCallback.component.d.ts.map +1 -0
  54. package/dist/core/default-component/SilentCallback.component.js +96 -0
  55. package/dist/core/default-component/SilentCallback.component.js.map +1 -0
  56. package/dist/core/default-component/index.d.ts +7 -0
  57. package/dist/core/default-component/index.d.ts.map +1 -0
  58. package/dist/core/default-component/index.js +20 -0
  59. package/dist/core/default-component/index.js.map +1 -0
  60. package/dist/core/routes/OidcRoutes.d.ts +12 -0
  61. package/dist/core/routes/OidcRoutes.d.ts.map +1 -0
  62. package/dist/core/routes/OidcRoutes.js +71 -0
  63. package/dist/core/routes/OidcRoutes.js.map +1 -0
  64. package/dist/core/routes/index.d.ts +3 -0
  65. package/dist/core/routes/index.d.ts.map +1 -0
  66. package/dist/core/routes/index.js +9 -0
  67. package/dist/core/routes/index.js.map +1 -0
  68. package/dist/core/routes/route-utils.d.ts +2 -0
  69. package/dist/core/routes/route-utils.d.ts.map +1 -0
  70. package/dist/core/routes/route-utils.js +32 -0
  71. package/dist/core/routes/route-utils.js.map +1 -0
  72. package/dist/core/routes/withRouter.d.ts +19 -0
  73. package/dist/core/routes/withRouter.d.ts.map +1 -0
  74. package/dist/core/routes/withRouter.js +33 -0
  75. package/dist/core/routes/withRouter.js.map +1 -0
  76. package/dist/index.d.ts +6 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +19 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/vanilla/index.d.ts +2 -0
  81. package/dist/vanilla/index.d.ts.map +1 -0
  82. package/dist/vanilla/index.js +6 -0
  83. package/dist/vanilla/index.js.map +1 -0
  84. package/dist/vanilla/initSession.d.ts +11 -0
  85. package/dist/vanilla/initSession.d.ts.map +1 -0
  86. package/dist/vanilla/initSession.js +72 -0
  87. package/dist/vanilla/initSession.js.map +1 -0
  88. package/dist/vanilla/initWorker.d.ts +13 -0
  89. package/dist/vanilla/initWorker.d.ts.map +1 -0
  90. package/dist/vanilla/initWorker.js +211 -0
  91. package/dist/vanilla/initWorker.js.map +1 -0
  92. package/dist/vanilla/memoryStorageBackend.d.ts +10 -0
  93. package/dist/vanilla/memoryStorageBackend.d.ts.map +1 -0
  94. package/dist/vanilla/memoryStorageBackend.js +33 -0
  95. package/dist/vanilla/memoryStorageBackend.js.map +1 -0
  96. package/dist/vanilla/noHashQueryStringUtils.d.ts +5 -0
  97. package/dist/vanilla/noHashQueryStringUtils.d.ts.map +1 -0
  98. package/dist/vanilla/noHashQueryStringUtils.js +31 -0
  99. package/dist/vanilla/noHashQueryStringUtils.js.map +1 -0
  100. package/dist/vanilla/oidc.d.ts +77 -0
  101. package/dist/vanilla/oidc.d.ts.map +1 -0
  102. package/dist/vanilla/oidc.js +814 -0
  103. package/dist/vanilla/oidc.js.map +1 -0
  104. package/dist/vanilla/timer.d.ts +8 -0
  105. package/dist/vanilla/timer.d.ts.map +1 -0
  106. package/dist/vanilla/timer.js +135 -0
  107. package/dist/vanilla/timer.js.map +1 -0
  108. package/package.json +73 -0
  109. package/src/App.css +38 -0
  110. package/src/App.specold.tsx +46 -0
  111. package/src/App.tsx +61 -0
  112. package/src/FetchUser.tsx +53 -0
  113. package/src/Home.tsx +20 -0
  114. package/src/MultiAuth.tsx +114 -0
  115. package/src/Profile.tsx +77 -0
  116. package/src/configurations.ts +53 -0
  117. package/src/index.css +13 -0
  118. package/src/index.tsx +9 -0
  119. package/src/logo.svg +7 -0
  120. package/src/oidc/FetchToken.tsx +51 -0
  121. package/src/oidc/OidcProvider.tsx +165 -0
  122. package/src/oidc/OidcSecure.tsx +32 -0
  123. package/src/oidc/ReactOidc.tsx +112 -0
  124. package/src/oidc/User.ts +38 -0
  125. package/src/oidc/core/default-component/AuthenticateError.component.tsx +13 -0
  126. package/src/oidc/core/default-component/Authenticating.component.tsx +13 -0
  127. package/src/oidc/core/default-component/Callback.component.tsx +49 -0
  128. package/src/oidc/core/default-component/Loading.component.tsx +10 -0
  129. package/src/oidc/core/default-component/ServiceWorkerInstall.component.tsx +51 -0
  130. package/src/oidc/core/default-component/ServiceWorkerNotSupported.component.tsx +13 -0
  131. package/src/oidc/core/default-component/SessionLost.component.tsx +14 -0
  132. package/src/oidc/core/default-component/SilentCallback.component.tsx +31 -0
  133. package/src/oidc/core/default-component/index.ts +6 -0
  134. package/src/oidc/core/routes/OidcRoutes.spec.tsx +16 -0
  135. package/src/oidc/core/routes/OidcRoutes.tsx +69 -0
  136. package/src/oidc/core/routes/__snapshots__/OidcRoutes.spec.tsx.snap +7 -0
  137. package/src/oidc/core/routes/index.ts +2 -0
  138. package/src/oidc/core/routes/route-utils.spec.ts +9 -0
  139. package/src/oidc/core/routes/route-utils.ts +34 -0
  140. package/src/oidc/core/routes/withRouter.spec.tsx +48 -0
  141. package/src/oidc/core/routes/withRouter.tsx +60 -0
  142. package/src/oidc/index.ts +5 -0
  143. package/src/oidc/vanilla/OidcServiceWorker.js +272 -0
  144. package/src/oidc/vanilla/OidcTrustedDomains.js +6 -0
  145. package/src/oidc/vanilla/index.ts +1 -0
  146. package/src/oidc/vanilla/initSession.ts +36 -0
  147. package/src/oidc/vanilla/initWorker.ts +153 -0
  148. package/src/oidc/vanilla/memoryStorageBackend.ts +33 -0
  149. package/src/oidc/vanilla/noHashQueryStringUtils.ts +7 -0
  150. package/src/oidc/vanilla/oidc.ts +600 -0
  151. package/src/oidc/vanilla/timer.ts +157 -0
  152. package/src/override/AuthenticateError.component.tsx +14 -0
  153. package/src/override/Authenticating.component.tsx +14 -0
  154. package/src/override/Callback.component.tsx +13 -0
  155. package/src/override/Loading.component.tsx +13 -0
  156. package/src/override/ServiceWorkerNotSupported.component.tsx +15 -0
  157. package/src/override/SessionLost.component.tsx +21 -0
  158. package/src/override/style.ts +10 -0
  159. package/src/setupTests.js +5 -0
  160. package/tsconfig.json +38 -0
package/README.md ADDED
@@ -0,0 +1,502 @@
1
+ <H1> @axa-fr/react-oidc-context</H1>
2
+
3
+ Try the demo at https://black-rock-0dc6b0d03.1.azurestaticapps.net/
4
+
5
+ <p align="center">
6
+ <img src="https://github.com/AxaGuilDEv/react-oidc/blob/master/docs/img/introduction.gif?raw=true"
7
+ alt="Sample React Oicd"
8
+ />
9
+ </p>
10
+
11
+ <p align="center">
12
+ A set of react components to make Oidc (OpenID Connect) client easy. It aim to simplify OAuth authentication between multiples providers.
13
+ </p>
14
+
15
+ - [About](#about)
16
+ - [Getting Started](#getting-started)
17
+ - [Run The Demo](#run-the-demo)
18
+ - [Examples](#examples)
19
+ - [How It Works](#how-it-works)
20
+ - [Service Worker Support](#service-worker-support)
21
+
22
+ Easy set up of OIDC for react and use the new react context api as state management.
23
+ It use AppAuthJS behind the scene.
24
+
25
+ - **Secure** :
26
+ - With the use of Service Worker, your tokens (refresh_token and access_token) are not accessible to the javascript client code (big protection against XSRF attacks)
27
+ - OIDC using client side Code Credential Grant with pkce only
28
+ - **Lightweight**
29
+ - **Simple** :
30
+ - refresh_token and access_token are auto refreshed in background
31
+ - with the use of the Service Worker, you do not need to inject the access_token in every fetch, you have only to configure OidcTrustedDomains.js file
32
+ - **No cookies problem** : You can disable silent signin (that internally use an iframe)
33
+ - **Multiple Authentification** :
34
+ - You can authenticate many times to the same provider with different scope (for exemple you can acquire a new 'payment' scope for a payment)
35
+ - You can authenticate to multiple different providers inside the same SPA (single page application) website
36
+ - **Flexible** :
37
+ - Work with Service Worker (more secure) and whithout for older browser (less secure)
38
+
39
+ <p align="center">
40
+ <img src="https://github.com/AxaGuilDEv/react-oidc/blob/master/docs/img/schema_pcke_client_side_with_service_worker.png?raw=true"
41
+ alt="Schema Authorization Code Grant with pcke flow on the using service worker"
42
+ />
43
+ <br>
44
+ The service worker catch <b>access_token</b> and <b>refresh_token</b> that will never be accessible to the client.
45
+ </p>
46
+
47
+ # Getting Started
48
+
49
+ ```sh
50
+ npm install @axa-fr/react-oidc-context copyfiles --save
51
+ ```
52
+
53
+ If you need a very secure mode where refresh_token and access_token will be hide behind a service worker that will proxify requests.
54
+
55
+ Add a copy task in order to install and stay up to date an Oidc Service Worker.
56
+ The only file you should edit is "OidcTrustedDomains.js" which will never be erased with following configuration bellow.
57
+
58
+ ```sh
59
+ #package.json
60
+ {
61
+ "scripts": {
62
+ "copy": "copyfiles -f ./node_modules/@axa-fr/react-oidc-context/dist/OidcServiceWorker.js ./public && copyfiles -f -s ./node_modules/@axa-fr/react-oidc-context/dist/OidcTrustedDomains.js ./public",
63
+ "start:server": "react-scripts start",
64
+ "build:server": "npm run copy && react-scripts build",
65
+ "prepare": "npm run copy"
66
+ }
67
+ }
68
+ ```
69
+
70
+ ```javascript
71
+ // OidcTrustedDomains.js
72
+ // Add here trusted domains, access tokens will be send to
73
+ const trustedDomains = {
74
+ default:["http://localhost:4200"]
75
+ };
76
+ ```
77
+
78
+ # Run The Demo
79
+
80
+ ```sh
81
+ git clone https://github.com/AxaGuilDEv/react-oidc.git
82
+ cd react-oidc/packages/context
83
+ npm install
84
+ npm start
85
+ # then navigate to http://localhost:4200
86
+ ```
87
+
88
+ # Examples
89
+
90
+ ## Application startup
91
+
92
+ The library is router agnostic and use native History API.
93
+
94
+ The default routes used internally :
95
+
96
+ - www.your-app.fr/authentication/callback
97
+
98
+ ```javascript
99
+ import React from 'react';
100
+ import { render } from 'react-dom';
101
+ import { BrowserRouter as Router } from 'react-router-dom';
102
+ import { OidcProvider } from '@axa-fr/react-oidc-context';
103
+ import Header from './Layout/Header';
104
+ import Routes from './Router';
105
+
106
+ // This configuration use hybrid mode
107
+ // ServiceWorker are used if available (more secure) else tokens are given to the client
108
+ // You need to give inside your code the "access_token" when using fetch
109
+ const configuration = {
110
+ client_id: 'interactive.public.short',
111
+ redirect_uri: 'http://localhost:4200/authentication/callback',
112
+ silent_redirect_uri: 'http://localhost:4200/authentication/silent-callback',
113
+ scope: 'openid profile email api offline_access', // offline_access scope allow your client to retrieve the refresh_token
114
+ authority: 'https://demo.identityserver.io',
115
+ service_worker_relative_url:'/OidcServiceWorker.js',
116
+ service_worker_only:false,
117
+ };
118
+
119
+ const App = () => (
120
+ <OidcProvider configuration={configuration} >
121
+ <Router>
122
+ <Header />
123
+ <Routes />
124
+ </Router>
125
+ </OidcProvider>
126
+ );
127
+
128
+ render(<App />, document.getElementById('root'));
129
+ ```
130
+
131
+
132
+ ```javascript
133
+ const propTypes = {
134
+ loadingComponent: PropTypes.elementType, // you can inject your own loading component
135
+ sessionLostComponent: PropTypes.elementType, // you can inject your own session lost component
136
+ authenticating: PropTypes.elementType, // you can inject your own authenticationg component
137
+ callbackSuccessComponent: PropTypes.elementType, // you can inject your own call back success component
138
+ callbackErrorComponent: PropTypes.elementType, // you can inject your own call back error component
139
+ serviceWorkerNotSupportedComponent: PropTypes.elementType, // you can inject your page that explain your require a more modern browser
140
+ onSessionLost: PropTypes.function, // If set "sessionLostComponent" is not displayed and onSessionLost callback is called instead
141
+ configuration: PropTypes.shape({
142
+ client_id: PropTypes.string.isRequired, // oidc client id
143
+ redirect_uri: PropTypes.string.isRequired, // oidc redirect url
144
+ silent_redirect_uri: PropTypes.string, // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore sessions
145
+ silent_signin_timeout: PropTypes.number, // Optional default is 12000 milliseconds
146
+ scope: PropTypes.string.isRequired, // oidc scope (you need to set "offline_access")
147
+ authority: PropTypes.string.isRequired,
148
+ authority_configuration: PropTypes.shape({ // Optional for providers that does not implement OIDC server auto discovery via a .wellknowurl
149
+ authorization_endpoint: PropTypes.string,
150
+ token_endpoint: PropTypes.string,
151
+ userinfo_endpoint: PropTypes.string,
152
+ end_session_endpoint: PropTypes.string,
153
+ revocation_endpoint: PropTypes.string,
154
+ }),
155
+ refresh_time_before_tokens_expiration_in_second: PropTypes.number,
156
+ service_worker_relative_url: PropTypes.string,
157
+ service_worker_only: PropTypes.boolean, // default false
158
+ extras: StringMap|undefined // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that are send to the oidc server (more info: https://github.com/openid/AppAuth-JS)
159
+ }).isRequired
160
+ };
161
+ ```
162
+ ## How to consume
163
+
164
+ "useOidc" returns all props from the Hook :
165
+
166
+ ```javascript
167
+ import React from 'react';
168
+ import {useOidc} from "./oidc";
169
+
170
+ export const Home = () => {
171
+
172
+ const { login, logout, isAuthenticated} = useOidc();
173
+
174
+ return (
175
+ <div className="container-fluid mt-3">
176
+ <div className="card">
177
+ <div className="card-body">
178
+ <h5 className="card-title">Welcome !!!</h5>
179
+ <p className="card-text">React Demo Application protected by OpenId Connect</p>
180
+ {!isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => login('/profile')}>Login</button>}
181
+ {isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => logout()}>logout</button>}
182
+ </div>
183
+ </div>
184
+ </div>
185
+ )
186
+ };
187
+
188
+ ```
189
+ The Hook method exposes :
190
+ - isAuthenticated : if the user is logged in or not
191
+ - logout: logout function (return a promise)
192
+ - login: login function 'return a promise'
193
+
194
+ ## How to secure a component
195
+
196
+ "OidcSecure" component trigger authentication in case user is not authenticated. So, the children of that component can be accessible only once you are connected.
197
+
198
+ ```javascript
199
+ import React from 'react';
200
+ import { OidcSecure } from '@axa-fr/react-oidc-context';
201
+
202
+ const AdminSecure = () => (
203
+ <OidcSecure>
204
+ <h1>My sub component</h1>}
205
+ </OidcSecure>
206
+ );
207
+
208
+ // adding the oidc user in the props
209
+ export default AdminSecure;
210
+ ```
211
+
212
+ ## How to secure a component : HOC method
213
+
214
+ "withOidcSecure" act the same as "OidcSecure" it also trigger authentication in case user is not authenticated.
215
+
216
+ ```javascript
217
+ import React from 'react';
218
+ import { Switch, Route } from 'react-router-dom';
219
+ import { withOidcSecure } from '@axa-fr/react-oidc-context';
220
+ import Home from '../Pages/Home';
221
+ import Dashboard from '../Pages/Dashboard';
222
+ import Admin from '../Pages/Admin';
223
+
224
+ const Routes = () => (
225
+ <Switch>
226
+ <Route exact path="/" component={Home} />
227
+ <Route path="/dashboard" component={withOidcSecure(Dashboard)} />
228
+ <Route path="/admin" component={Admin} />
229
+ <Route path="/home" component={Home} />
230
+ </Switch>
231
+ );
232
+
233
+ export default Routes;
234
+ ```
235
+
236
+ ## How to get "Access Token" : Hook method
237
+
238
+ ```javascript
239
+ import { useOidcAccessToken } from '@axa-fr/react-oidc-context';
240
+
241
+ const DisplayAccessToken = () => {
242
+ const{ accessToken, accessTokenPayload } = useOidcAccessToken();
243
+
244
+ if(!accessToken){
245
+ return <p>you are not authentified</p>
246
+ }
247
+ return (
248
+ <div className="card text-white bg-info mb-3">
249
+ <div className="card-body">
250
+ <h5 className="card-title">Access Token</h5>
251
+ <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>
252
+ {<p className="card-text">{JSON.stringify(accessToken)}</p>}
253
+ {accessTokenPayload != null && <p className="card-text">{JSON.stringify(accessTokenPayload)}</p>}
254
+ </div>
255
+ </div>
256
+ )
257
+ };
258
+ ```
259
+
260
+ ## How to get IDToken : Hook method
261
+
262
+ ```javascript
263
+ import { useOidcIdToken } from '@axa-fr/react-oidc-context';
264
+
265
+ const DisplayIdToken =() => {
266
+ const{ idToken, idTokenPayload } = useOidcIdToken();
267
+
268
+ if(!idToken){
269
+ return <p>you are not authentified</p>
270
+ }
271
+
272
+ return (
273
+ <div className="card text-white bg-info mb-3">
274
+ <div className="card-body">
275
+ <h5 className="card-title">ID Token</h5>
276
+ {<p className="card-text">{JSON.stringify(idToken)}</p>}
277
+ {idTokenPayload != null && <p className="card-text">{JSON.stringify(idTokenPayload)}</p>}
278
+ </div>
279
+ </div>
280
+ );
281
+ }
282
+
283
+ ```
284
+
285
+
286
+ ## How to get User Information : Hook method
287
+
288
+ ```javascript
289
+ import { useOidcUser, UserStatus } from '@axa-fr/react-oidc-context';
290
+
291
+ const DisplayUserInfo = () => {
292
+ const{ oidcUser, oidcUserLoadingState } = useOidcUser();
293
+
294
+ switch (oidcUserLoadingState){
295
+ case UserStatus.Loading:
296
+ return <p>User Information are loading</p>;
297
+ case UserStatus.Unauthenticated:
298
+ return <p>you are not authenticated</p>;
299
+ case UserStatus.LoadingError:
300
+ return <p>Fail to load user information</p>;
301
+ default:
302
+ return (
303
+ <div className="card text-white bg-success mb-3">
304
+ <div className="card-body">
305
+ <h5 className="card-title">User information</h5>
306
+ <p className="card-text">{JSON.stringify(oidcUser)}</p>
307
+ </div>
308
+ </div>
309
+ );
310
+ }
311
+ };
312
+
313
+ ```
314
+
315
+ ## How to get a fetch that inject Access_Token : Hook method
316
+
317
+ If your are not using the service worker. Fetch function need to send AccessToken.
318
+ This Hook give you a wrapped fetch that add the access token for you.
319
+
320
+ ```javascript
321
+ import React, {useEffect, useState} from 'react';
322
+ import { useOidcFetch, OidcSecure } from '@axa-fr/react-oidc-context';
323
+
324
+ const DisplayUserInfo = ({ fetch }) => {
325
+ const [oidcUser, setOidcUser] = useState(null);
326
+ const [isLoading, setLoading] = useState(true);
327
+
328
+ useEffect(() => {
329
+ const fetchUserInfoAsync = async () => {
330
+ const res = await fetch("https://demo.duendesoftware.com/connect/userinfo");
331
+ if (res.status != 200) {
332
+ return null;
333
+ }
334
+ return res.json();
335
+ };
336
+ let isMounted = true;
337
+ fetchUserInfoAsync().then((userInfo) => {
338
+ if(isMounted) {
339
+ setLoading(false);
340
+ setOidcUser(userInfo)
341
+ }
342
+ })
343
+ return () => {
344
+ isMounted = false;
345
+ };
346
+ },[]);
347
+
348
+ if(isLoading){
349
+ return <>Loading</>;
350
+ }
351
+
352
+ return (
353
+ <div className="container mt-3">
354
+ <div className="card text-white bg-success mb-3">
355
+ <div className="card-body">
356
+ <h5 className="card-title">User information</h5>
357
+ {oidcUser != null && <p className="card-text">{JSON.stringify(oidcUser)}</p>}
358
+ </div>
359
+ </div>
360
+ </div>
361
+ )
362
+ };
363
+
364
+ export const FetchUserHook= () => {
365
+ const {fetch} = useOidcFetch();
366
+ return <OidcSecure><DisplayUserInfo fetch={fetch} /></OidcSecure>
367
+ }
368
+
369
+ ```
370
+
371
+ ## How to get a fetch that inject Access_Token : HOC method
372
+
373
+ If your are not using the service worker. Fetch function need to send AccessToken.
374
+ This HOC give you a wrapped fetch that add the access token for you.
375
+
376
+ ```javascript
377
+ import React, {useEffect, useState} from 'react';
378
+ import { useOidcFetch, OidcSecure } from '@axa-fr/react-oidc-context';
379
+
380
+ const DisplayUserInfo = ({ fetch }) => {
381
+ const [oidcUser, setOidcUser] = useState(null);
382
+ const [isLoading, setLoading] = useState(true);
383
+
384
+ useEffect(() => {
385
+ const fetchUserInfoAsync = async () => {
386
+ const res = await fetch("https://demo.duendesoftware.com/connect/userinfo");
387
+ if (res.status != 200) {
388
+ return null;
389
+ }
390
+ return res.json();
391
+ };
392
+ let isMounted = true;
393
+ fetchUserInfoAsync().then((userInfo) => {
394
+ if(isMounted) {
395
+ setLoading(false);
396
+ setOidcUser(userInfo)
397
+ }
398
+ })
399
+ return () => {
400
+ isMounted = false;
401
+ };
402
+ },[]);
403
+
404
+ if(isLoading){
405
+ return <>Loading</>;
406
+ }
407
+
408
+ return (
409
+ <div className="container mt-3">
410
+ <div className="card text-white bg-success mb-3">
411
+ <div className="card-body">
412
+ <h5 className="card-title">User information</h5>
413
+ {oidcUser != null && <p className="card-text">{JSON.stringify(oidcUser)}</p>}
414
+ </div>
415
+ </div>
416
+ </div>
417
+ )
418
+ };
419
+
420
+ const UserInfoWithFetchHoc = withOidcFetch(fetch)(DisplayUserInfo);
421
+ export const FetchUserHoc= () => <OidcSecure><UserInfoWithFetchHoc/></OidcSecure>;
422
+
423
+ ```
424
+
425
+
426
+ ## Components override
427
+
428
+ You can inject your own components.
429
+ All components definition receive props "configurationName". Please checkout and the the demo for more complexe exemple.
430
+
431
+ ```javascript
432
+
433
+ import React from 'react';
434
+ import { render } from 'react-dom';
435
+ import { BrowserRouter as Router } from 'react-router-dom';
436
+ import { OidcProvider } from '@axa-fr/react-oidc-context';
437
+ import Header from './Layout/Header';
438
+ import Routes from './Router';
439
+
440
+ // This configuration use hybrid mode
441
+ // ServiceWorker are used if available (more secure) else tokens are given to the client
442
+ // You need to give inside your code the "access_token" when using fetch
443
+ const configuration = {
444
+ client_id: 'interactive.public.short',
445
+ redirect_uri: 'http://localhost:4200/authentication/callback',
446
+ silent_redirect_uri: 'http://localhost:4200/authentication/silent-callback',
447
+ scope: 'openid profile email api offline_access',
448
+ authority: 'https://demo.identityserver.io',
449
+ service_worker_relative_url:'/OidcServiceWorker.js',
450
+ service_worker_only:false,
451
+ };
452
+
453
+ const Loading = () => <p>Loading</p>
454
+ const AuthenticatingError = () => <p>Authenticating error</p>
455
+ const Authenticating = () => <p>Authenticating</p>
456
+ const SessionLost = () => <p>Session Lost</p>
457
+ const ServiceWorkerNotSupported = () => <p>Not supported</p>
458
+ const CallBackSuccess = () => <p>Success</p>
459
+
460
+ //const [isSessionLost, setIsSessionLost] = useState(false);
461
+
462
+ //const onSessionLost = ()=>{
463
+ // setIsSessionLost(true);
464
+ //}
465
+
466
+ const App = () => (
467
+ <OidcProvider configuration={configuration}
468
+ loadingComponent={Loading}
469
+ authenticatingErrorComponent={AuthenticatingError}
470
+ authenticatingComponent={Authenticating}
471
+ sessionLostComponent={SessionLost}
472
+ //onSessionLost={onSessionLost} // If set "sessionLostComponent" is not displayed and onSessionLost callback is called instead
473
+ serviceWorkerNotSupportedComponent={ServiceWorkerNotSupported}
474
+ callbackSuccessComponent={CallBackSuccess}
475
+ >
476
+ {/* isSessionLost && <SessionLost />*/}
477
+ <Router>
478
+ <Header />
479
+ <Routes />
480
+ </Router>
481
+ </OidcProvider>
482
+ );
483
+
484
+ render(<App />, document.getElementById('root'));
485
+
486
+ ```
487
+
488
+ # How It Works
489
+
490
+ These components encapsulate the use of "AppAuth-JS" in order to hide workfow complexity.
491
+ Internally, native History API is used to be router library agnostic.
492
+
493
+ More information about OIDC
494
+ - French: https://medium.com/just-tech-it-now/augmentez-la-s%C3%A9curit%C3%A9-et-la-simplicit%C3%A9-de-votre-syst%C3%A8me-dinformation-avec-oauth-2-0-cf0732d71284
495
+ - English: https://medium.com/just-tech-it-now/increase-the-security-and-simplicity-of-your-information-system-with-openid-connect-fa8c26b99d6d
496
+
497
+ # Service Worker Support
498
+
499
+ - Firefox : tested on firefox 98.0.2
500
+ - Chrome/Edge : tested on version upper to 90
501
+ - Opera : tested on version upper to 80
502
+ - Safari : tested on Safari/605.1.15
@@ -0,0 +1,10 @@
1
+ /// <reference types="react" />
2
+ export declare type Fetch = typeof window.fetch;
3
+ export interface ComponentWithOidcFetchProps {
4
+ fetch?: Fetch;
5
+ }
6
+ export declare const withOidcFetch: (fetch?: Fetch, configurationName?: string) => (WrappedComponent: any) => (props: ComponentWithOidcFetchProps) => JSX.Element;
7
+ export declare const useOidcFetch: (fetch?: Fetch, configurationName?: string) => {
8
+ fetch: (url: RequestInfo, options?: RequestInit) => Promise<Response>;
9
+ };
10
+ //# sourceMappingURL=FetchToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FetchToken.d.ts","sourceRoot":"","sources":["../src/oidc/FetchToken.tsx"],"names":[],"mappings":";AAGA,oBAAY,KAAK,GAAG,OAAO,MAAM,CAAC,KAAK,CAAC;AACxC,MAAM,WAAW,2BAA2B;IAC1C,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AA8BD,eAAO,MAAM,aAAa,WAAU,KAAK,oEAE1B,2BAA2B,gBAGvC,CAAC;AAGJ,eAAO,MAAM,YAAY,WAAS,KAAK;iBAlC9B,WAAW,YACP,WAAW;CAuCvB,CAAA"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (_) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.useOidcFetch = exports.withOidcFetch = void 0;
54
+ var react_1 = __importDefault(require("react"));
55
+ var oidc_1 = __importDefault(require("./vanilla/oidc"));
56
+ var defaultConfigurationName = "default";
57
+ var fetchWithToken = function (fetch, getAccessTokenInjected) { return function (url, options) {
58
+ if (options === void 0) { options = { method: 'GET' }; }
59
+ return __awaiter(void 0, void 0, void 0, function () {
60
+ var headers, optionTmp, accessToken, newOptions;
61
+ return __generator(this, function (_a) {
62
+ switch (_a.label) {
63
+ case 0:
64
+ headers = new Headers();
65
+ optionTmp = __assign({}, options);
66
+ if (optionTmp.headers) {
67
+ headers = !(optionTmp.headers instanceof Headers)
68
+ ? new Headers(optionTmp.headers)
69
+ : optionTmp.headers;
70
+ }
71
+ accessToken = getAccessTokenInjected();
72
+ if (!headers.has('Accept')) {
73
+ headers.set('Accept', 'application/json');
74
+ }
75
+ if (accessToken) {
76
+ headers.set('Authorization', "Bearer ".concat(accessToken));
77
+ if (!optionTmp.credentials) {
78
+ optionTmp.credentials = 'same-origin';
79
+ }
80
+ }
81
+ newOptions = __assign(__assign({}, optionTmp), { headers: headers });
82
+ return [4 /*yield*/, fetch(url, newOptions)];
83
+ case 1: return [2 /*return*/, _a.sent()];
84
+ }
85
+ });
86
+ });
87
+ }; };
88
+ var withOidcFetch = function (fetch, configurationName) {
89
+ if (fetch === void 0) { fetch = null; }
90
+ if (configurationName === void 0) { configurationName = defaultConfigurationName; }
91
+ return function (WrappedComponent) { return function (props) {
92
+ var newFetch = (0, exports.useOidcFetch)(fetch || props.fetch, configurationName).fetch;
93
+ return react_1.default.createElement(WrappedComponent, __assign({}, props, { fetch: newFetch }));
94
+ }; };
95
+ };
96
+ exports.withOidcFetch = withOidcFetch;
97
+ var useOidcFetch = function (fetch, configurationName) {
98
+ if (fetch === void 0) { fetch = null; }
99
+ if (configurationName === void 0) { configurationName = defaultConfigurationName; }
100
+ var previousFetch = fetch || window.fetch;
101
+ var getOidc = oidc_1.default.get;
102
+ var getAccessTokenInjected = function () { return getOidc(configurationName).tokens.accessToken; };
103
+ var newFetch = fetchWithToken(previousFetch, getAccessTokenInjected);
104
+ return { fetch: newFetch };
105
+ };
106
+ exports.useOidcFetch = useOidcFetch;
107
+ //# sourceMappingURL=FetchToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FetchToken.js","sourceRoot":"","sources":["../src/oidc/FetchToken.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAA0B;AAC1B,wDAAkC;AAMlC,IAAM,wBAAwB,GAAG,SAAS,CAAC;AAE3C,IAAM,cAAc,GAAG,UAAC,KAAY,EAAE,sBAA2C,IAAK,OAAA,UAClF,GAAgB,EAChB,OAAwC;IAAxC,wBAAA,EAAA,YAAyB,MAAM,EAAE,KAAK,EAAE;;;;;;oBAEtC,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;oBACtB,SAAS,gBAAQ,OAAO,CAAE,CAAC;oBAEjC,IAAI,SAAS,CAAC,OAAO,EAAE;wBACrB,OAAO,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,YAAY,OAAO,CAAC;4BAC7C,CAAC,CAAC,IAAI,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;4BAChC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC;qBACzB;oBAEK,WAAW,GAAG,sBAAsB,EAAE,CAAC;oBAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;wBAC1B,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;qBAC3C;oBACD,IAAI,WAAW,EAAE;wBACf,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,iBAAU,WAAW,CAAE,CAAC,CAAC;wBACtD,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;4BAC1B,SAAS,CAAC,WAAW,GAAG,aAAa,CAAC;yBACvC;qBACF;oBACK,UAAU,yBAAQ,SAAS,KAAE,OAAO,SAAA,GAAE,CAAC;oBACtC,qBAAM,KAAK,CAAC,GAAG,EAAE,UAAU,CAAC,EAAA;wBAAnC,sBAAO,SAA4B,EAAC;;;;CACrC,EAzBqF,CAyBrF,CAAC;AAEK,IAAM,aAAa,GAAG,UAAC,KAAgB,EAAE,iBAA0C;IAA5D,sBAAA,EAAA,YAAgB;IAAE,kCAAA,EAAA,4CAA0C;IAAK,OAAA,UAC3F,gBAAgB,IACb,OAAA,UAAC,KAAkC;QAC/B,IAAM,QAAQ,GAAI,IAAA,oBAAY,EAAC,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,iBAAiB,CAAC,MAAzD,CAAyD;QAC9E,OAAO,8BAAC,gBAAgB,eAAK,KAAK,IAAE,KAAK,EAAE,QAAQ,IAAI,CAAC;IAC1D,CAAC,EAHI,CAGJ;AAL4F,CAK5F,CAAC;AALS,QAAA,aAAa,iBAKtB;AAGG,IAAM,YAAY,GAAE,UAAC,KAAgB,EAAE,iBAA0C;IAA5D,sBAAA,EAAA,YAAgB;IAAE,kCAAA,EAAA,4CAA0C;IACtF,IAAM,aAAa,GAAG,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;IAC5C,IAAM,OAAO,GAAI,cAAI,CAAC,GAAG,CAAC;IAC1B,IAAM,sBAAsB,GAAG,cAAQ,OAAO,OAAO,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC/F,IAAM,QAAQ,GAAG,cAAc,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC;IACvE,OAAO,EAAE,KAAK,EAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC,CAAA;AANY,QAAA,YAAY,gBAMxB"}
@@ -0,0 +1,25 @@
1
+ import { ComponentType, FC, PropsWithChildren } from 'react';
2
+ import { OidcConfiguration } from './vanilla/oidc';
3
+ export declare type oidcContext = {
4
+ getOidc: Function;
5
+ };
6
+ export declare type OidcProviderProps = {
7
+ callbackSuccessComponent?: ComponentType<any>;
8
+ callbackErrorComponent?: ComponentType<any>;
9
+ sessionLostComponent?: ComponentType<any>;
10
+ authenticatingComponent?: ComponentType<any>;
11
+ loadingComponent?: ComponentType<any>;
12
+ authenticatingErrorComponent?: ComponentType<any>;
13
+ serviceWorkerNotSupportedComponent?: ComponentType<any>;
14
+ configurationName?: string;
15
+ configuration?: OidcConfiguration;
16
+ children: any;
17
+ onSessionLost?: Function;
18
+ };
19
+ export declare type OidcSessionProps = {
20
+ configurationName: string;
21
+ loadingComponent: PropsWithChildren<any>;
22
+ };
23
+ export declare const OidcProvider: FC<PropsWithChildren<OidcProviderProps>>;
24
+ export default OidcProvider;
25
+ //# sourceMappingURL=OidcProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OidcProvider.d.ts","sourceRoot":"","sources":["../src/oidc/OidcProvider.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAC,aAAa,EAAE,EAAE,EAAE,iBAAiB,EAAsB,MAAM,OAAO,CAAC;AACvF,OAAa,EAAC,iBAAiB,EAAC,MAAM,gBAAgB,CAAC;AAMvD,oBAAY,WAAW,GAAG;IACtB,OAAO,EAAE,QAAQ,CAAC;CACrB,CAAC;AAIF,oBAAY,iBAAiB,GAAG;IAC5B,wBAAwB,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9C,sBAAsB,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC5C,oBAAoB,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC1C,uBAAuB,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC7C,gBAAgB,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IACtC,4BAA4B,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAClD,kCAAkC,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IACxD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,QAAQ,EAAE,GAAG,CAAC;IACd,aAAa,CAAC,EAAE,QAAQ,CAAC;CAC5B,CAAC;AAEF,oBAAY,gBAAgB,GAAG;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC;CAC5C,CAAC;AAyCF,eAAO,MAAM,YAAY,EAAG,EAAE,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CA2FlE,CAAC;AAEF,eAAe,YAAY,CAAC"}