App infinitely redirecting after login

I have a user that is being infinitely redirected in our app. The webpage loads auth0, shows a pop up, then redirects the user again. It doesn’t end.
Every time it redirects, the ‘state’ value is different. Is there some way to decode this “state” and see what its doing?
Here’s a sample of ONE of address/state that we managed to grab during the infinite redirect:

https://[my website address]/?code=jPs0l9kQRmacT-wz&state=NGdZNnFSV25sMnMyOElXd1JJZHZ0MmZLdkRKb0Q5ckNEZGVIUDdYeFpCbw%3D%3D

Hi @truescope,

The state is only encoded if something is set by the client application in the /authorize request.

For example, when the client application passed the state abc123 in the authorization request:

tenant.auth0.com/authorize?...&state=abc123

Then it will be passed back to the client application with the redirect to the callback URL:

/callback?...&state=xyzABC123

You can read more about the state param in our docs:

In order to help troubleshoot what might be causing the loop, would you mind sharing which SDK you are using in your app?

Have you been able to replicate the issue in an incognito window? This behavior could be caused by blocked third-party cookies.

Are you seeing any related tenant logs of failed silent auth?

Thank you,

Stephanie

Hi @stephanie.chamblee
Thanks for your response.

I am using the “@auth0/auth0-react” library, v1.4.0.
I can easily reproduce the issue by

  • open a new incognito window using chrome v90.0.4430.212
  • navigate to my website https://[my site]
  • auth0’s sign in form appears in the page, so I enter the details and select ‘login’

Then:

  • it logs in
  • the site is redirected to https://[my site].com/?code=[my code]
  • but i think auth0 then tries to redirect the browser back to auth0’s login page, however, we’re already logged in, so it redirects back to the app. In the brief second that the window is redirecting, you can see “pop up blocked” in the address bar.

It seems to be fine for

  • chrome in normal browsing mode
  • firefox in normal browsing mode
  • firefox in ‘private browser’ mode

Maybe chrome in cognito isn’t passing the logged in state back to the react app properly? Any tips on how we can address this?

update 1: it looks like this thread has the exact same issue as us:

Thank you for the additional context, @truescope!

In the linked topic and in this case, it sounds like blocked third-party cookies could be the cause. To confirm, you can try adding the cacheLocation config to the Auth0Provider if you haven’t done so already:

const onRedirectCallback = (appState) => {
  history.replace(
    appState && appState.returnTo
      ? appState.returnTo
      : window.location.pathname
  );
};

ReactDOM.render(
  <Auth0Provider
    domain={config.domain}
    clientId={config.clientId}
    redirectUri={window.location.origin}
    audience={config.audience}
    scope="read:current_user update:current_user_metadata"
    onRedirectCallback={onRedirectCallback}
    useRefreshTokens={true}
    cacheLocation="localstorage" // <-- add this config
  >
    <App />
  </Auth0Provider>,
  document.getElementById("root")
);

Also, are there are any places that you are calling getAccessTokenSilently? If so, any scope or audience passed should be listed in the Auth0Provider.

Note: there are security considerations for using local storage to store tokens: Token Storage
If this is the issue, using a Custom Domain is the recommended approach.

1 Like

I’ve followed your recommendation by

  • adjusting the <Auth0Provider .../> to include useRefreshTokens={true} and cacheLocation="localstorage"
  • ensured that any scopes are also passed into the Auth0Provider (yes we do use getAccessTokenSilently)
  • we do actually use a custom domain

But it still seems to be stuck in an infinite redirect loop.

I’ve actually managed to isolate the issue into a new react app. (made with create-react-app)

index.js:

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import './index.css';
import { Auth0Provider } from "@auth0/auth0-react";
import config from './config.json';

const onRedirectCallback = (appState) => {
	window.history.replaceState({}, document.title, appState && appState.targetUrl ? appState.targetUrl : window.location.pathname);
};

ReactDOM.render(
  <Auth0Provider
  	connection={config.connection}
    domain={config.domain}
    clientId={config.clientId}
	auddience={config.audience}
    redirectUri={window.location.origin}
	onRedirectCallback={onRedirectCallback}
	useRefreshTokens={true}
	cacheLocation="localstorage"
  >
    <App />
  </Auth0Provider>,
  document.getElementById("root")
);

App.js

import logo from "./logo.svg";
import "./App.css";
import { useAuth0 } from "@auth0/auth0-react";
import { useEffect } from "react";
import config from './config.json';

const App = () => {

	const { isAuthenticated, isLoading, loginWithRedirect, logout, getAccessTokenSilently } = useAuth0();

	useEffect(() => {

		if(isLoading){
			console.log('app is loading');
			return;
		}

		if(!isAuthenticated){
			console.log('not authenticated. redirecting to login');
			loginWithRedirect();
			return;
		}

		//this causes an infinite loop:
		//getToken(config.customApi);

		//this causes an infinite loop:
		//getToken(config.managementApi);

		//this works fine
		getToken({});

	}, [isLoading, isAuthenticated]);

	const getToken = (options) => {
		console.log(`retrieving token for '${options.audience}'`);
		getAccessTokenSilently(options).then(token => {
			console.log('retrieved token!', token);
		})
		.catch(e => {
			console.error('failed to get token!', e);
		});
	};

	if(isLoading){
		return (<div>loading</div>);
	}

	if(!isAuthenticated){
		return (<div>you're not authenticated!</div>);
	}

	const handleLogoutClick = (e) => {
		e.preventDefault();
		logout();
	}

	const render = () => {
		return (
			<div className="App">
				<header className="App-header">
					<img src={logo} className="App-logo" alt="logo" />
					<p>
						Edit <code>src/App.js</code> and save to reload.
					</p>
					<button onClick={handleLogoutClick}>Log out</button>
				</header>
			</div>
		);
	};

	return render();
};

export default App;

config.json:

{
	"connection": "app",
    "domain": "ts-app-dev.au.auth0.com",
    "clientId": "(my client id)",
	"audience": "https://domain.com/api/v2/",
	"customApi": {
		"audience": "https://api.identifier"
	},
	"managementApi": {
		"audience": "https://domain/api/v2/"
	}
}

And the only package.json deps you need are:

    "@auth0/auth0-react": "^1.5.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3"
  },

Above - if you uncomment the lines App.js, you’ll get an infinite loop.
It seems that if you provide the audience option to getTokenSilently({ audience: ... ), while in “incognito mode” you get stuck in an infinite loop.

Note: in auth0 management interface, i have

  • a react app
  • the auth0 management api (i dont use this except for allowing users to reset their password)
  • a custom api (which contains all of my app’s functionality)
    So i have 2 audiences (one for custom api, one for management api)

Any suggestions?
I can send you guys the fully zipped project + a log in for my app if you like.

1 Like

Hi @truescope,

Thank you for sending this info and the code! I was able to spin up the example app.

In the Auth0Provider, if you update auddience to audience, you’ll be able to use:

getToken(config.managementApi);

Without an infinite loop.

When your app requests a token that has a different audience than what is specified in the Auth0Provider, the SDK will attempt to perform silent authentication to obtain an Access Token with the correct audience. However, if the app domain and your Auth0 tenant domain differ, than the browser may block the transfer of third-party cookies.

Since you are using a custom domain, this should not occur. I will have to investigate your settings some more to see what might be going on for sure.

Hi @truescope,

Are you passing the custom domain as the domain in the Auth0Provider?

Ahhh! Spelling error in auddience!

After fixing that, I was able to confirm that the overall issue was incorrectly using the management api’s audience, instead of my custom api’s audience as the Auth0Provider audience value. It seems to only appear as an issue in Chrome’s incognito mode.

Thanks for your help @stephanie.chamblee

2 Likes

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.