auth0 / auth0-react

Auth0 SDK for React Single Page Applications (SPA)
MIT License
866 stars 252 forks source link

login_hint is not working if set using global state or session storage. #743

Closed ropali-munshi closed 6 months ago

ropali-munshi commented 6 months ago

Checklist

Description

I am trying to use the login_hint in authorizationParams. I have a requirement of setting this param dynamically so that when the user goes to the auth0 login page then the email is prefilled. This works if I use a hardcoded value but fails when using a local/global state to populate that parameter.

I can see the login_hint param is set in the Auth0Provider component when the state changes using the Reactjs component debugger but when I call the loginWithRedirect() the /authorize URL has login_hint value empty. I have posted this issue in the Auth0 community forum here https://community.auth0.com/t/login-hint-param-is-always-empty-when-using-ulp-with-reactjs/127953 with code sample.

import React, {useState, useEffect} from 'react';
import {createRoot} from 'react-dom/client';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {Auth0Provider} from '@auth0/auth0-react';
import history from './utils/history';
import {getConfig} from './config';
import {EmailProvider, useEmail} from "./components/EmailContext";

const onRedirectCallback = (appState) => {
    console.log('onRedirectCallback called');
    history.push(appState && appState.returnTo ? appState.returnTo : window.location.pathname);
};

const config = getConfig();

// Custom wrapper component that includes an input for login_hint
const Auth0ProviderWithConfig = ({children}) => {
    const {email, setEmail} = useEmail();

    const providerConfig = {
        domain: config.domain,
        clientId: config.clientId,
        onRedirectCallback,
        authorizationParams: {
            login_hint: email,
            redirect_uri: window.location.origin,
            ...(config.audience ? {audience: config.audience} : null),
        },
    };
    console.log(providerConfig.authorizationParams)

    return (

        <Auth0Provider {...providerConfig}>
            {children}
        </Auth0Provider>

    );
};

const root = createRoot(document.getElementById('root'));
root.render(
    <EmailProvider>
        <Auth0ProviderWithConfig>
            <App/>
        </Auth0ProviderWithConfig>,\
    </EmailProvider>
);

serviceWorker.unregister();

I also tried to use session storage to see if this works or not. So when a user enters an email I store it in the session storage & try to fetch the value from it in the authorizationParams. It actually works sometimes & sometimes not.

Here is the code example

export const Auth0ProviderWithNavigate = ({children}) => {
    const navigate = useNavigate();

    const domain = import.meta.env.VITE_AUTH0_DOMAIN as string;
    const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID as string;
    const redirectUri = window.location.origin + routes.login
    const audience = import.meta.env.VITE_AUTH0_AUDIENCE as string;

    const onRedirectCallback = (appState: any) => {

        navigate(appState?.returnTo || redirectUri, {replace: true});
    };

    if (!(domain && clientId && redirectUri)) {
        return null;
    }

    return (
        <Auth0Provider
            domain={domain}
            clientId={clientId}
            authorizationParams={{
                redirect_uri: redirectUri,
                // using the session storage as global state is not working here
                login_hint: sessionStorage.getItem("userInputEmail") || "",
                audience: audience
            }}
            onRedirectCallback={onRedirectCallback}
        >
            {children}
        </Auth0Provider>
    );
};

Reproduction

Try to fill the login_hint param in the authorizationParams dynamically using either state variable or session storage.

Additional context

I am using Vite with Typescript for building the project.

auth0-react version

2.2.4

React version

18.2.0

Which browsers have you tested in?

Chrome

frederikprijck commented 6 months ago

You want to do this when calling loginWithRedirect and set the login_hint on authorizationParams in that function. The properties of the Auth0Provider do not support being changed over time.

ropali-munshi commented 6 months ago

@frederikprijck Is there any other way to do that? I don't understand why it does not support that. the only way to use login_hint is to use the hardcoded value which does not make much sense to me.

frederikprijck commented 6 months ago

the only way to use login_hint is to use the hardcoded value which does not make much sense to me.

The way to use a dynamic login_hint is to pass it to loginWithRedirect({ authorizationParams: { login_hint: sessionStorage.getItem("userInputEmail") }}). That should allow you to achieve what you want without having to rerender the Provider when the value changes.

ropali-munshi commented 6 months ago

@frederikprijck Thanks! It is working properly.