I'm struggling to get OIDC login working with React -- into day 4.
Now trying oidc-rect
and the problem that I have is that it assumes that the settings are hard-coded, but I need to load them from /settings
.
Here's the code for loading the settings
import { Context, createContext, useContext, useEffect, useState } from "react";
export class AppSettings {
buildName: string = '';
authority: string = '';
truthPortalApi: string = '';
environment: string = '';
}
export const AppSettingsContext: Context<AppSettings> = createContext<AppSettings>(null!)
export const AppSettingsProvider: React.FC<{ children: JSX.Element }> = ({ children }) => {
const [settings, setSettings] = useState<AppSettings>(new AppSettings())
useEffect(() => {
fetch(`${window.location.origin}/settings`)
.then(response => response.json())
.then(data => setSettings(data))
}, []);
return (
<AppSettingsContext.Provider value={ settings }>
{children}
</AppSettingsContext.Provider>
)
}
export function useAppSettings(): AppSettings {
return useContext<AppSettings>(AppSettingsContext);
}
And here's how I'm trying to use them
let url: string = `${window.location.protocol}//${window.location.host}/`;
function createUserManager(appSettings: AppSettings): UserManager {
const authSettings: UserManagerSettings = {
authority: appSettings.authority,
client_id: 'client_app',
redirect_uri: `${url}signin-callback`, // Guess. It's unclear what this should be.
silent_redirect_uri: `${url}silent-callback.html`, // Guess. It's unclear what this should be.
post_logout_redirect_uri: `${url}`,
response_type: 'code',
scope: 'openid profile offline_access app',
loadUserInfo: true
};
return new UserManager(authSettings);
}
export const LocalAuthProvider: React.FC<{ children: JSX.Element[] }> = ({ children }) => {
let appSettings: AppSettings = useAppSettings();
const [userManager, setUserManager] = useState<UserManager>(() => (appSettings && appSettings.authority) ? createUserManager(appSettings) : null!);
useEffect(() => () => {
if (appSettings && appSettings.authority) {
console.warn(`LocalAuthProvider setUserManager authority='${appSettings.authority}'`);
setUserManager(createUserManager(appSettings));
}
}, [appSettings]);
return (
<AuthProvider userManager={userManager} >
{children}
</AuthProvider >
);
}
However, it doesn't work because
Uncaught (in promise) Error: No authority or metadataUrl configured on settings
Clearly the problem is returning an AuthProvider
before the settings have loaded, but how do you fix this in React?
You can't just return {children}
because the children then get an error when they try to useAuth
.