diff --git a/MIGRATION_GUIDE_V3_TO_V5.md b/MIGRATION_GUIDE_V3_TO_V5.md new file mode 100644 index 000000000..1f8e25856 --- /dev/null +++ b/MIGRATION_GUIDE_V3_TO_V5.md @@ -0,0 +1,173 @@ +# Migrate from v3 to v5 + +V4 is a complete rewrite. It uses the libraries ["App-AuthJS"](https://github.com/openid/AppAuth-JS) instead of oidc-client. +In the v4 we have chosen to remove a lot the surface API in order to simplify usage and enforce security. + +- Packages + - [`@axa-fr/react-oidc-context`](./packages/context#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-context.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-context) + - [`@axa-fr/vanilla-oidc`](./packages/vanilla#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Fvanilla-oidc.svg)](https://badge.fury.io/js/%40axa-fr%2Fvanilla-oidc) + - [`@axa-fr/react-oidc-context-fetch`](./packages/context-fetch#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-context-fetch.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-context-fetch) **Deprecated in v4** + - [`@axa-fr/react-oidc-redux`](./packages/redux#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-redux.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-redux) **Deprecated in v4 : use react-oidc-context which works with redux and in fact does not use any react context** + - [`@axa-fr/react-oidc-redux-fetch`](./packages/redux-fetch#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-redux-fetch.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-redux-fetch) **Deprecated in v4** + - [`@axa-fr/react-oidc-fetch-observable`](./packages/fetch-observable#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-fetch-observable.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-fetch-observable) **Deprecated in v4** + +Migration PullRequest sample : https://github.com/samuel-gomez/react-starter-toolkit/pull/36 + + +Main provider component have been renamed +```javascript +import { AuthenticationProvider } from '@axa-fr/react-oidc-context'; + +// old v3 + + + + +// in v4 become + +import { OidcProvider } from '@axa-fr/react-oidc-context'; + +//loggerLevel : Logger property has been removed in v4 + + +``` + +Provider properties have changed, you need to keep only required properties for v4 else it won't work. +```javascript +// old v3 +const propTypes = { + notAuthenticated: PropTypes.elementType, // react component displayed during authentication + notAuthorized: PropTypes.elementType, // react component displayed in case user is not Authorised + authenticating: PropTypes.elementType, // react component displayed when about to redirect user to be authenticated + callbackComponentOverride: PropTypes.elementType, // react component displayed when user is connected + sessionLostComponent: PropTypes.elementType, // react component displayed when user loose authentication session + configuration: PropTypes.shape({ + client_id: PropTypes.string.isRequired, // oidc client configuration, the same as oidc client library used internally https://github.com/IdentityModel/oidc-client-js + redirect_uri: PropTypes.string.isRequired, + response_type: PropTypes.string.isRequired, + scope: PropTypes.string.isRequired, + authority: PropTypes.string.isRequired, + silent_redirect_uri: PropTypes.string.isRequired, + automaticSilentRenew: PropTypes.bool, //optional, by default to true + loadUserInfo: PropTypes.bool, //optional, by default to true + post_logout_redirect_uri: PropTypes.string, // optional + metadata: PropTypes.shape({ + issuer: PropTypes.string, + jwks_uri: PropTypes.string, + authorization_endpoint: PropTypes.string, + token_endpoint: PropTypes.string, + userinfo_endpoint: PropTypes.string, + end_session_endpoint: PropTypes.string, + revocation_endpoint: PropTypes.string, + introspection_endpoint: PropTypes.string, + }), + }).isRequired, + isEnabled: PropTypes.bool, // enable/disable the protections and trigger of authentication (useful during development). + loggerLevel: PropTypes.number, + logger: PropTypes.shape({ + info: PropTypes.func.isRequired, + warn: PropTypes.func.isRequired, + error: PropTypes.func.isRequired, + debug: PropTypes.func.isRequired, + }), + UserStore: PropTypes.func, +}; + +// new v4 +const propTypes = { + loadingComponent: PropTypes.elementType, // you can inject your own loading component + sessionLostComponent: PropTypes.elementType, // you can inject your own session lost component + authenticating: PropTypes.elementType, // you can inject your own authenticationg component + callbackSuccessComponent: PropTypes.elementType, // you can inject your own call back success component + callbackErrorComponent: PropTypes.elementType, // you can inject your own call back error component + serviceWorkerNotSupportedComponent: PropTypes.elementType, // you can inject your page that explain your require a more modern browser + configuration: PropTypes.shape({ + client_id: PropTypes.string.isRequired, // oidc client id + redirect_uri: PropTypes.string.isRequired, // oidc redirect url + silent_redirect_uri: PropTypes.string, // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore sessions + scope: PropTypes.string.isRequired, // oidc scope (you need to set "offline_access") + authority: PropTypes.string.isRequired, + refresh_time_before_tokens_expiration_in_second: PropTypes.number, + service_worker_relative_url: PropTypes.string, + service_worker_only: PropTypes.boolean, // default false + 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) + }).isRequired +}; +``` + + +Manage Oidc actions and informations + +```javascript + +// old v3 +import { useReactOidc } from '@axa-fr/react-oidc-context'; +const { isEnabled, login, logout, oidcUser, events } = useReactOidc(); + + +// new v45 +import { useOidc, useOidcAccessToken, useOidcIdToken, useOidcUser } from '@axa-fr/react-oidc-context'; + +const { login, logout, isAuthenticated} = useOidc(); // login and logout return a Promise +const{ oidcUser, oidcUserLoadingState } = useOidcUser(); // Return user_info endpoint data +const{ accessToken, accessTokenPayload } = useOidcAccessToken(); // Contain access_token metadata acess_token is a jwk +const{ idToken, idTokenPayload } = useOidcIdToken(); // contain IDToken metadata + + ``` +```javascript + +// old v3 +import { withFetchRedirectionOn401, + withFetchSilentAuthenticateAndRetryOn401, + withFetchRedirectionOn403, + withAuthentication } from '@axa-fr/react-oidc-context-fetch'; + + +// new v4 +import { withOidcFetch } from '@axa-fr/react-oidc-context'; + + +// withFetchRedirectionOn401 : removed, you have to implement your own 401 management +// withFetchSilentAuthenticateAndRetryOn401 : removed, not necessary in v4 token are in auto refresh mode only +// withFetchRedirectionOn403 : removed, you have to implement your own 403 management +// withAuthentication : removed + +// withFetchToken in v3 have been rename to withOidcFetch and set inside '@axa-fr/react-oidc-context' package +withOidcFetch() + + +``` + +If you need a very secure mode where refresh_token and access_token will be hide behind a service worker that will proxify requests. + +Add a copy task in order to install and stay up to date an Oidc Service Worker. +The only file you should edit is "OidcTrustedDomains.js" which will never be erased with the configuration bellow. + +```sh +#package.json +{ + "scripts": { + "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", + "start:server": "react-scripts start", + "build:server": "npm run copy && react-scripts build", + "prepare": "npm run copy" + } +} +``` + +Then edit OidcTrustedDomains.js in "public" folder for your need + +```javascript +// OidcTrustedDomains.js +// Add here trusted domains, access tokens will be send to +const trustedDomains = { + default:["http://localhost:4200"], +}; +``` + + +In case v4 does not implement all features that you are using or this migration guide enought complete. + +Please make issues or PullRequest in order to help to complete it ! + + diff --git a/MIGRATION_GUIDE_V4_TO_V5.md b/MIGRATION_GUIDE_V4_TO_V5.md new file mode 100644 index 000000000..e46015056 --- /dev/null +++ b/MIGRATION_GUIDE_V4_TO_V5.md @@ -0,0 +1,24 @@ +# Migrate from v4 to v5 + +V5 is a small refactor renaming. + +```javascript + +// old v4 + +const { login, logout, isLogged} = useOidc(); + +// in v4 become + +const { login, logout, isAuthenticated} = useOidc(); +``` + +Provider properties have changed, you need to keep only required properties for v4 else it won't work. +```javascript +// old v3 +const{ oidcUser, isOidcUserLoading, isLogged } = useOidcUser(); + +// new v4 +const{ oidcUser, oidcUserLoadingState } = useOidcUser(); +``` + diff --git a/packages/context/README.md b/packages/context/README.md index 79e31fe0e..ada0d4a41 100644 --- a/packages/context/README.md +++ b/packages/context/README.md @@ -238,7 +238,7 @@ const DisplayAccessToken = () => {
Access Token

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.

- {accessToken != null &&

{JSON.stringify(accessToken)}

} + {

{JSON.stringify(accessToken)}

} {accessTokenPayload != null &&

{JSON.stringify(accessTokenPayload)}

}
@@ -262,7 +262,7 @@ const DisplayIdToken =() => {
ID Token
- {idToken != null &&

{JSON.stringify(idToken)}

} + {

{JSON.stringify(idToken)}

} {idTokenPayload != null &&

{JSON.stringify(idTokenPayload)}

}
@@ -275,29 +275,30 @@ const DisplayIdToken =() => { ## How to get User Information : Hook method ```javascript -import { useOidcUser } from '@axa-fr/react-oidc-context'; +import { useOidcUser, UserStatus } from '@axa-fr/react-oidc-context'; const DisplayUserInfo = () => { - const{ oidcUser, isOidcUserLoading } = useOidcUser(); - - if(isOidcUserLoading !== UserStatus.Loaded) { - return

User Information are loading

- } - - if(!oidcUser){ - return

you are not authenticated

- } - - return ( -
-
-
User information
-

{oidcUser == null && "You are not logged" }

- {oidcUser != null &&

{JSON.stringify(oidcUser)}

} -
-
- ) + const{ oidcUser, oidcUserLoadingState } = useOidcUser(); + + switch (oidcUserLoadingState){ + case UserStatus.Loading: + return

User Information are loading

; + case UserStatus.Unauthenticated: + return

you are not authenticated

; + case UserStatus.LoadingError: + return

Fail to load user information

; + default: + return ( +
+
+
User information
+

{JSON.stringify(oidcUser)}

+
+
+ ); + } }; + ``` # Service Worker Support diff --git a/packages/context/src/Profile.tsx b/packages/context/src/Profile.tsx index 5ae51672d..67c17963f 100644 --- a/packages/context/src/Profile.tsx +++ b/packages/context/src/Profile.tsx @@ -1,32 +1,28 @@ import React from 'react'; -import {OidcSecure, useOidc, useOidcAccessToken, useOidcIdToken, useOidcUser} from "./oidc"; -import {UserStatus} from "./oidc/User"; +import {OidcSecure, useOidcAccessToken, useOidcIdToken, useOidcUser, UserStatus} from "./oidc"; + const DisplayUserInfo = () => { const{ oidcUser, oidcUserLoadingState } = useOidcUser(); - if(oidcUserLoadingState === UserStatus.Loading) { - return

User Information are loading

- } - - if(oidcUserLoadingState === UserStatus.LoadingError) { - return

User Information loading errored.

- } - - if(!oidcUser){ - return

you are not authenticated

+ switch (oidcUserLoadingState){ + case UserStatus.Loading: + return

User Information are loading

; + case UserStatus.Unauthenticated: + return

you are not authenticated

; + case UserStatus.LoadingError: + return

Fail to load user information

; + default: + return ( +
+
+
User information
+

{JSON.stringify(oidcUser)}

+
+
+ ); } - - return ( -
-
-
User information
-

{oidcUser == null && "You are not logged" }

- {oidcUser != null &&

{JSON.stringify(oidcUser)}

} -
-
- ) }; export const Profile = () => { @@ -51,7 +47,7 @@ const DisplayAccessToken = () => {
Access Token

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.

- {accessToken != null &&

Access Token: {JSON.stringify(accessToken)}

} + {

Access Token: {JSON.stringify(accessToken)}

} {accessTokenPayload != null &&

Access Token Payload: {JSON.stringify(accessTokenPayload)}

}
@@ -70,7 +66,7 @@ const DisplayIdToken =() => {
ID Token
- {idToken != null &&

IdToken: {JSON.stringify(idToken)}

} + {

IdToken: {JSON.stringify(idToken)}

} {idTokenPayload != null &&

IdToken Payload: {JSON.stringify(idTokenPayload)}

}
diff --git a/packages/context/src/oidc/index.ts b/packages/context/src/oidc/index.ts index 03612b62d..90dd835f4 100644 --- a/packages/context/src/oidc/index.ts +++ b/packages/context/src/oidc/index.ts @@ -1,5 +1,5 @@ export { withOidcSecure, OidcSecure } from "./OidcSecure"; -export { useOidcUser } from "./User"; +export { useOidcUser, UserStatus } from "./User"; export { useOidc, useOidcAccessToken, useOidcIdToken } from "./ReactOidc"; export { withOidcFetch, fetchWithToken } from "./FetchToken"; export { OidcProvider } from "./OidcProvider"; diff --git a/readme.md b/readme.md index caa961f23..6a5284ff7 100644 --- a/readme.md +++ b/readme.md @@ -37,6 +37,8 @@ In the v4 we have chosen to remove a lot the surface API in order to simplify us In this version you can use a ServiceWorker that will hide the refresh_token and access_token (more secure). For migrating from v3 to v4 checkout our [`migration guide v3 to v4`](./MIGRATION_GUIDE_V3_TO_V4.md) +For migrating from v3 to v5 checkout our [`migration guide v3 to v5`](./MIGRATION_GUIDE_V3_TO_V5.md) +For migrating from v4 to v5 checkout our [`migration guide v4 to v5`](./MIGRATION_GUIDE_V4_TO_V5.md) - **Secure** : - 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) @@ -155,7 +157,7 @@ const DisplayIdToken =() => {
ID Token
- {idToken != null &&

{JSON.stringify(idToken)}

} + {

{JSON.stringify(idToken)}

} {idTokenPayload != null &&

{JSON.stringify(idTokenPayload)}

}
@@ -170,27 +172,28 @@ How to get User Information import { useOidcUser } from '@axa-fr/react-oidc-context'; const DisplayUserInfo = () => { - const{ oidcUser, isOidcUserLoading, isLogged } = useOidcUser(); - - if(isOidcUserLoading) { - return

User Information are loading

- } - - if(!isLogged){ - return

you are not authentified

- } - - return ( -
-
-
User information
- {oidcUser != null &&

{JSON.stringify(oidcUser)}

} -
-
- ) + const{ oidcUser, oidcUserLoadingState } = useOidcUser(); + + switch (oidcUserLoadingState){ + case UserStatus.Loading: + return

User Information are loading

; + case UserStatus.Unauthenticated: + return

you are not authenticated

; + case UserStatus.LoadingError: + return

Fail to load user information

; + default: + return ( +
+
+
User information
+

{JSON.stringify(oidcUser)}

+
+
+ ); + } }; -``` +``` More documentation : - [`@axa-fr/react-oidc-context`](./packages/context#readme)