Skip to content

Commit

Permalink
refactor(hook): rename isLogged to isAuthenticated + refactor useOidc…
Browse files Browse the repository at this point in the history
…User hook (#743)

BREAKING
* feat(isauthenticated-separate): Adding separate hook to check if user is authenticated.
The "useOidc()" hook is more noisy - it re-renders more because of the three state it has to manage. We could decouple these.
* feat(isauthenticated-separate): Updating readme.
* fix(isauthenticated-separate): Removing unnecessary hook and optimizing 'getOidcUser()'.
This commit contains breaking changes: "isLogged" is switched to "isAuthenticated", per request.
* fix(isauthenticated-separate): Removing unnecessary component in demo.
* fix(isauthenticated-separate): Object property refactor and adding new user state.
  • Loading branch information
LuchoTurtle authored Apr 1, 2022
1 parent 1e6e64d commit cee3d5c
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 64 deletions.
19 changes: 10 additions & 9 deletions packages/context/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,16 @@ import {useOidc} from "./oidc";

export const Home = () => {

const { login, logout, isLogged} = useOidc();
const { login, logout, isAuthenticated} = useOidc();

return (
<div className="container-fluid mt-3">
<div className="card">
<div className="card-body">
<h5 className="card-title">Welcome !!!</h5>
<p className="card-text">React Demo Application protected by OpenId Connect</p>
{!isLogged && <button type="button" className="btn btn-primary" onClick={() => login('/profile')}>Login</button>}
{isLogged && <button type="button" className="btn btn-primary" onClick={logout}>logout</button>}
{!isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => login('/profile')}>Login</button>}
{isAuthenticated && <button type="button" className="btn btn-primary" onClick={logout}>logout</button>}
</div>
</div>
</div>
Expand All @@ -176,7 +176,7 @@ export const Home = () => {

```
The Hook method exposes :
- isLogged : is the user logged?
- isAuthenticated : if the user is logged in or not
- logout: logout function (return a promise)
- login: login function 'return a promise'

Expand Down Expand Up @@ -278,20 +278,21 @@ const DisplayIdToken =() => {
import { useOidcUser } from '@axa-fr/react-oidc-context';
const DisplayUserInfo = () => {
const{ oidcUser, isOidcUserLoading, isLogged } = useOidcUser();
const{ oidcUser, isOidcUserLoading } = useOidcUser();
if(isOidcUserLoading) {
if(isOidcUserLoading !== UserStatus.Loaded) {
return <p>User Information are loading</p>
}
if(!isLogged){
return <p>you are not authentified</p>
if(!oidcUser){
return <p>you are not authenticated</p>
}
return (
<div className="card text-white bg-success mb-3">
<div className="card-body">
<h5 className="card-title">User information</h5>
<p>{oidcUser == null && "You are not logged" }</p>
{oidcUser != null && <p className="card-text">{JSON.stringify(oidcUser)}</p>}
</div>
</div>
Expand All @@ -304,4 +305,4 @@ const DisplayUserInfo = () => {
- Firefox : tested on firefox 98.0.2
- Chrome/Edge : tested on version upper to 90
- Opera : tested on version upper to 80
- Safari : tested on Safari/605.1.15
- Safari : tested on Safari/605.1.15
4 changes: 2 additions & 2 deletions packages/context/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions packages/context/src/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import {useOidc} from "./oidc";

export const Home = () => {

const { login, logout, isLogged} = useOidc();
const { login, logout, isAuthenticated} = useOidc();

return (
<div className="container-fluid mt-3">
<div className="card">
<div className="card-body">
<h5 className="card-title">Home</h5>
<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</a> </p>
{!isLogged && <button type="button" className="btn btn-primary" onClick={() => login('/profile')}>Login</button>}
{isLogged && <button type="button" className="btn btn-primary" onClick={logout}>logout</button>}
{!isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => login('/profile')}>Login</button>}
{isAuthenticated && <button type="button" className="btn btn-primary" onClick={logout}>logout</button>}
</div>
</div>
</div>
Expand Down
20 changes: 10 additions & 10 deletions packages/context/src/MultiAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ import {OidcProvider, useOidc, useOidcAccessToken} from "./oidc";
import { configurationIdentityServer} from "./configurations";

const MultiAuth = ( {configurationName, handleConfigurationChange }) => {
const { login, logout, isLogged} = useOidc(configurationName);
const { login, logout, isAuthenticated} = useOidc(configurationName);
return (
<div className="container-fluid mt-3">
<div className="card">
<div className="card-body">
<h5 className="card-title">Work in progress</h5>
<p className="card-text">React Demo Application protected by OpenId Connect with MultipleAUthentication.
<p className="card-text">React Demo Application protected by OpenId Connect with MultipleAUthentication.
<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>
<select value={configurationName} onChange={handleConfigurationChange} >
<option value="config_1">config_1</option>
<option value="config_2">config_2</option>
</select>
{!isLogged && <button type="button" className="btn btn-primary" onClick={() => login()}>Login</button>}
{isLogged && <button type="button" className="btn btn-primary" onClick={logout}>logout</button>}
{!isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => login()}>Login</button>}
{isAuthenticated && <button type="button" className="btn btn-primary" onClick={logout}>logout</button>}
</div>
</div>
</div>
Expand All @@ -32,21 +32,21 @@ export const MultiAuthContainer = () => {
const callBack = window.location.origin+"/multi-auth/authentification/callback2";
const silent_redirect_uri = window.location.origin+"/multi-auth/authentification/silent-callback2";
const configurations = {
config_1: {...configurationIdentityServer,
redirect_uri:callBack,
config_1: {...configurationIdentityServer,
redirect_uri:callBack,
silent_redirect_uri,
scope: 'openid profile email api offline_access'
},
config_2: {...configurationIdentityServer,
redirect_uri:callBack,
silent_redirect_uri: "",
config_2: {...configurationIdentityServer,
redirect_uri:callBack,
silent_redirect_uri: "",
scope: 'openid profile email api'}
}
const handleConfigurationChange = (event) => {
const configurationName = event.target.value;
sessionStorage.configurationName = configurationName;
setConfigurationName(configurationName);

}
return (
<OidcProvider configuration={configurations[configurationName]} configurationName={configurationName}>
Expand Down
23 changes: 14 additions & 9 deletions packages/context/src/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import React from 'react';

import {OidcSecure, useOidcAccessToken, useOidcIdToken, useOidcUser} from "./oidc";
import {OidcSecure, useOidc, useOidcAccessToken, useOidcIdToken, useOidcUser} from "./oidc";
import {UserStatus} from "./oidc/User";

const DisplayUserInfo = () => {
const{ oidcUser, isOidcUserLoading, isLogged } = useOidcUser();
const{ oidcUser, oidcUserLoadingState } = useOidcUser();

if(isOidcUserLoading) {
if(oidcUserLoadingState === UserStatus.Loading) {
return <p>User Information are loading</p>
}

if(!isLogged){
return <p>you are not authentified</p>
if(oidcUserLoadingState === UserStatus.LoadingError) {
return <p>User Information loading errored.</p>
}

if(!oidcUser){
return <p>you are not authenticated</p>
}

return (
Expand Down Expand Up @@ -39,7 +44,7 @@ const DisplayAccessToken = () => {
const{ accessToken, accessTokenPayload } = useOidcAccessToken();

if(!accessToken){
return <p>you are not authentified</p>
return <p>you are not authenticated</p>
}
return (
<div className="card text-white bg-info mb-3">
Expand All @@ -58,9 +63,9 @@ const DisplayIdToken =() => {
const{ idToken, idTokenPayload } = useOidcIdToken();

if(!idToken){
return <p>you are not authentified</p>
return <p>you are not authenticated</p>
}

return (
<div className="card text-white bg-info mb-3">
<div className="card-body">
Expand All @@ -73,4 +78,4 @@ const DisplayIdToken =() => {
}


export const SecureProfile = () => <OidcSecure><Profile /></OidcSecure>;
export const SecureProfile = () => <OidcSecure><Profile /></OidcSecure>;
22 changes: 11 additions & 11 deletions packages/context/src/oidc/ReactOidc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ import Oidc from "./vanilla/oidc";
const defaultConfigurationName = "default";
export const useOidc =(configurationName=defaultConfigurationName) =>{
const getOidc = Oidc.get;

const login = (callbackPath=undefined) => {
return getOidc(configurationName).loginAsync(callbackPath);
};
const logout = () => {
return getOidc(configurationName).logoutAsync();
};
let isLogged = false;

let isAuthenticated = false;
const oidc = getOidc(configurationName);
if(oidc){
isLogged = getOidc(configurationName).tokens != null;
isAuthenticated = getOidc(configurationName).tokens != null;
}
return {login, logout, isLogged };

return { login, logout, isAuthenticated };
}

const accessTokenInitialState = {accessToken:null, accessTokenPayload:null};
Expand All @@ -37,7 +37,7 @@ export const useOidcAccessToken =(configurationName=defaultConfigurationName) =>
const getOidc = Oidc.get;
const [state, setAccessToken] = useState<any>(initTokens(configurationName));
const [subscriptionId, setSubscriptionId] = useState(null);

useEffect(() => {
let isMounted = true;
const oidc = getOidc(configurationName);
Expand All @@ -60,7 +60,7 @@ export const useOidcAccessToken =(configurationName=defaultConfigurationName) =>
if(isMounted){
setSubscriptionId(newSubscriptionId);
}
return () => {
return () => {
isMounted = false;
oidc.removeEventSubscription(subscriptionId);
};
Expand All @@ -84,14 +84,14 @@ export const useOidcIdToken =(configurationName= defaultConfigurationName) =>{
const getOidc = Oidc.get;
const [state, setIDToken] = useState<any>(idTokenInitialState);
const [subscriptionId, setSubscriptionId] = useState(initIdToken(configurationName));

useEffect(() => {
let isMounted = true;
const oidc = getOidc(configurationName);
if(oidc.tokens) {
const tokens = oidc.tokens;
setIDToken({idToken: tokens.idToken, idTokenPayload:tokens.idTokenPayload});
}
}
if(subscriptionId){
oidc.removeEventSubscription(subscriptionId);
}
Expand All @@ -113,4 +113,4 @@ export const useOidcIdToken =(configurationName= defaultConfigurationName) =>{
};
}, [configurationName]);
return state;
}
}
45 changes: 26 additions & 19 deletions packages/context/src/oidc/User.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
import { useEffect, useState} from "react";
import Oidc from "./vanilla/oidc";

export const useOidcUser =(configurationName="default") => {
const [oidcUser, setOidcUser] = useState(null);
const [isOidcUserLoading, setIsOidcUserLoading] = useState(false);
const getOidc = Oidc.get;
export enum UserStatus {
Unauthenticated= 'Unauthenticated',
Loading = 'Loading user',
Loaded = 'User loaded',
LoadingError = 'Error loading user'
}

type OidcUser = {
user: any,
status: UserStatus
}

export const useOidcUser = (configurationName="default") => {
const [oidcUser, setOidcUser] = useState<OidcUser>({user: null, status: UserStatus.Unauthenticated});

const oidc = Oidc.get(configurationName);
useEffect(() => {
let isMounted = true;
const oidc = getOidc(configurationName);

if(oidc && oidc.tokens) {
setIsOidcUserLoading(true);
getOidc().userInfoAsync()
setOidcUser({...oidcUser, status: UserStatus.Loading});
oidc.userInfoAsync()
.then((info) => {
if (isMounted) {
setOidcUser(info);
setIsOidcUserLoading(false);
setOidcUser({user: info, status: UserStatus.Loaded});
}
})
.catch(() => setOidcUser({...oidcUser, status: UserStatus.LoadingError}));
}

return () => { isMounted = false };
}, [])

let isLogged = false;
const oidc = getOidc(configurationName);
if(oidc){
isLogged = oidc.tokens != null;
}

return {oidcUser, isOidcUserLoading, isLogged: isLogged}
}
}, []);

return {oidcUser: oidcUser.user, oidcUserLoadingState: oidcUser.status}
}

0 comments on commit cee3d5c

Please sign in to comment.