Description
Checklist
- The issue can be reproduced in the auth0-angular sample app (or N/A).
- I have looked into the Readme, Examples, and FAQ and have not found a suitable solution or answer.
- I have looked into the API documentation and have not found a suitable solution or answer.
- I have searched the issues and have not found a suitable solution or answer.
- I have searched the Auth0 Community forums and have not found a suitable solution or answer.
- I agree to the terms within the Auth0 Code of Conduct.
Description
I followed the instructions with how to setup Auth0 in a capacitor + Angular app listed here: https://auth0.com/docs/quickstart/native/ionic-angular. I then added the AuthGuard to my root path, because I wanted all of my main routes to be protected. After completing a successful login, the app redirects a second time to the login screen, and then immediately redirects back (or makes you select your organization again if doing that flow).
Expected behavor: The app should not need to authenticate you twice in a row.
Reproduction
- Setup the sample capacitor + angular demo app: https://auth0.com/docs/quickstart/native/ionic-angular
- Setup your main route to be protected by the AuthGuard
// app.routes.ts
export const APP_ROUTES: Route[] = [
{
path: 'login-failed',
component: LoginFailedComponent
},
{
path: 'logout',
component: LogoutComponent
},
{
path: '',
runGuardsAndResolvers: 'always',
canActivate: [AuthGuard],
children: [
{
path: 'tenant-select',
component: TenantSelectComponent
},
{
path: 'usage',
component: UsageComponent
},
// ... More routes
{
path: '',
pathMatch: 'full',
redirectTo: 'tenant-select'
}
]
},
{
path: '**',
redirectTo: 'tenant-select'
}
];
- Launch the app and login. Once logged in, you will be redirect back to the login page again.
Additional context
Looking through the auth0 code, this is happening because of the following sequence of events:
- The app launches, goes to '/' route. This triggers the AuthGuard to call loginWithRedirect, because it's not authenticated: https://github.com/auth0/auth0-angular/blob/main/projects/auth0-angular/src/lib/auth.guard.ts#L45
- After successfully logging in, the
appUrlOpen
code executeshandleRedirectCallback
:
ngOnInit(): void {
// Use Capacitor's App plugin to subscribe to the `appUrlOpen` event
App.addListener('appUrlOpen', ({ url }) => {
// Must run inside an NgZone for Angular to pick up the changes
// https://capacitorjs.com/docs/guides/angular
ngZone.run(() => {
if (url?.startsWith(callbackUri)) {
// If the URL is an authentication callback URL..
if (
url.includes('state=') &&
(url.includes('error=') || url.includes('code='))
) {
// Call handleRedirectCallback and close the browser
this.auth
.handleRedirectCallback(url)
.pipe(mergeMap(() => Browser.close()))
.subscribe();
} else {
Browser.close();
}
}
});
});
}
- The code in
handleRedirectCallback
callsthis.authState.refresh();
(this ASYNCHRONOUSLY updates the state), and then continues to SYNCHRONOUSLY redirect back to '/'. Nothing waits for the state to be updated before redirecting to '/'. https://github.com/auth0/auth0-angular/blob/main/projects/auth0-angular/src/lib/auth.service.ts#L305 - The redirect to '/' triggers the AuthGuard to execute again, checking the
isAuthenticated$
observable (which is still false), and triggers theloginWithRedirect
AGAIN.
As best as I can tell from running the code, since isAuthenticated$
uses shareReplay(1)
, the AuthGuard is getting the replayed value of false BEFORE the isAuthenticatedTrigger$
can be re-run from the authState.refresh()
call.
auth0-angular version
2.2.3
Angular version
19.1.3
Which browsers have you tested in?
Safari, Edge