1

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.

Richard Barraclough
  • 2,625
  • 3
  • 36
  • 54

0 Answers0