
Describe the bug
When a user first logs in using auth0, they are redirected correctly to auth0's login page and redirected back and authenticated as expected. If the user logs out, then clicks on login again, next-auth doesn't redirect the user to login page again; it automatically logs the user in.
This can be reproduced on the example application
Steps to reproduce
auth0Sign In again (The user is not sent to the login page)Expected behavior
The user is redirected to the login page whenever they click on sign in.
Hi there, thanks for taking the time to provide detail and a video!
So, this is correct and expected behaviour from NextAuth.js - and it's actually down to Auth0 returning a callback immediately.
I appreciate it is however slightly weird flow in the case of Auth0.
There are a couple of options if you don't want this behaviour:
You can call a logout method for the provider.
NextAuth.js does not currently do this and there are few cases that this would be appropriate and even possible; only Auth0 and perhaps a corporate Open ID service spring to mind, but it's something we could support as an option for providers that support it future (e.g. by implementing the OpenID Connect Logout flow).
It's an edge case - with most providers (Twitter, Facebook, Google, Apple, etc) it's not a flow you can trigger - so it's not currently a priority but I'd welcome support for it.
You can (and this is probably easier) usually configure the provider to always prompt by specifying a custom authorizationUrl on the Auth0 provider (overriding the default). I don't know how this works for Auth0 - I looked it up but the documentation doesn't say what the options are.
To do this for Google, you would change this:
authorizationUrl: 'https://accounts.google.com/o/oauth2/auth?response_type=code'
to this:
authorizationUrl: 'https://accounts.google.com/o/oauth2/auth?response_type=code&prompt=consent'
Several provider have options like this, including Microsoft, which also supports values of 'consent', 'login', 'select_account' and 'none'. https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
The default authorizationUrl for Auth0 looks like this:
authorizationUrl: https://${options.domain}/authorize?response_type=code'
The only supported option I can see for Auth0 is 'none'. As it's a commercial service it's probably best to ask them about it and what the options are. This is the page for it, but it doesn't have any info about other options:
https://auth0.com/docs/api/authentication#authorization-code-flow
prompt=consent also works with Auth0. You can find more info about it here.
Thanks @LoriKarikari! Do we think Auth0 is a special case where maybe we should add it by default for the provider?
I don't have a strong view on it.
Very happy to add that to the docs for it though - that would seem to make sense!
@iaincollins reading the page that I linked it seems that the current flow is the default behavior for Auth0.
@iaincollins So is there a solution to this using any of the available features in nextauth or does it still need to implemented?
@kizzlebot You can do this in NextAuth.js, as described above.
e.g.
import Providers from `next-auth/providers`
...
providers: [
Providers.Auth0({
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
domain: process.env.AUTH0_DOMAIN,
authorizationUrl: `https://${process.env.AUTH0_DOMAIN}/authorize?response_type=code&prompt=consent`
})
}
...
@iaincollins doesn't seem to solve my issue. When I log out and try to log in again, it prompts me for consent like I've never logged out. And there is no way to log out once logged in.

This is whats in my pages/api/auth/[...nextAuth].js file
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
const options = {
// https://next-auth.js.org/configuration/providers
providers: [
Providers.Auth0({
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
domain: process.env.AUTH0_DOMAIN,
authorizationUrl: `https://${process.env.AUTH0_DOMAIN}/authorize?response_type=code&prompt=consent`
})
],
// Enable debug messages in the console if you are having problems
debug: true,
}
export default (req, res) => NextAuth(req, res, options)
I don't think prompt=consent is necessarily the solution for this. I believe the issue is that next-auth does not have a logoutUrl property to invalidate a user's session held by the authentication providers. I had trouble finding concise documentation from Auth0 on the matter so here's are good explanations from the FusionAuth folks and AWS Cognito.
FusionAuth Logout: https://fusionauth.io/docs/v1/tech/oauth/endpoints#logout
Cognito Logout: https://fusionauth.io/docs/v1/tech/oauth/endpoints#logout
I can think of two possible reasons why it might be a good idea to add a logout flow for providers who support logout flows. Please correct me if I'm wrong!
Account switching: Some users may want to switch account for a particular application. When attempting to sign in right after signing out (session still active), the user is immediately authorized without being prompted with a login screen. As a result, the user cannot enter a different username/email without clearing cookies. Some users may get frustrated by the idea of having to clear their browser cache to switch account.
Security: The OAuth provider is not informed of a logout operation so I don't think the user's session is getting properly terminated. This can present a potential security issue for shared workstations i.e. internet cafes and public libraries. Someone could potentially login as the previous user of a shared workstation by simply clicking the login button on the same site.
Possible solution 1: To include an optional logoutUrl property for relevant providers in the pages/api/auth/[...nextAuth].js config. This would be configured to initiate and handle the logout flow. i.e.
logoutUrl: `https://${process.env.COGNITO_DOMAIN}/logout?client_id=${process.env.COGNITO_CLIENT_ID}`
Possible solution 2: Passing the req and res parameters into event callbacks. This might encourage next-auth users to add complex logic in the event callbacks which may not be ideal.
Possible solution 3: To provide some way to programmatically distinguish a signIn operation from a signOut operation during the "redirect" callback. The two arguments to the redirect callback are _url_ and _baseUrl_, but perhaps it could include an additional argument such as _eventType_ which enumerates the type of event that invoked the redirect callback. This might encourage next-auth users to add complex logic in the redirect callback which may not be ideal.
My current workaround: I was able to successfully implement the pages/api/logout endpoint myself for both FusionAuth and Cognito.
async function handleLogout(req, res) {
// Uncomment for FusionAuth
// res.redirect(`http://${process.env.FUSIONAUTH_DOMAIN}/oauth2/logout?client_id=${process.env.FUSIONAUTH_CLIENT_ID}`);
// Uncomment for Cognito
res.redirect(`https://${process.env.COGNITO_DOMAIN}/logout?client_id=${process.env.COGNITO_CLIENT_ID}&logout_uri=${process.env.COGNITO_LOGOUT_URL}`);
}
export default async function logout(req, res) {
try {
await handleLogout(req, res);
} catch (error) {
console.error(error);
res.status(error.status || 400).end(error.message);
}
}
NOTES TO COGNITO USERS
https://${process.env.COGNITO_DOMAIN}/logout?client_id=${process.env.COGNITO_CLIENT_ID}&logout_uri=${process.env.COGNITO_LOGOUT_URL}I solved this for Auth0 by setting the authorizationUrl's prompt parameter to login which always shows the authentication page as described here (These are the docs for the new universal login experience but it also works for classic).
Providers.Auth0({
/* ... */
authorizationUrl: `https://${process.env.AUTH0_DOMAIN}/authorize?response_type=code&prompt=login`
}),
Maybe this should be added as a tip to https://github.com/nextauthjs/next-auth/blob/main/www/docs/providers/auth0.md...?
After reading https://github.com/nextauthjs/next-auth/blob/main/www/docs/configuration/providers.md#oauth-provider-options which describes the params property of the provider options as "Additional authorization URL parameters" I initially thought I could add prompt: 'login' there but that didn't work. What is that object used for?
Hi @iaincollins @NickBolles, May I know how you handle the type infer for this ?
Providers.Auth0({
/* ... */
authorizationUrl: `https://${process.env.AUTH0_DOMAIN}/authorize?response_type=code&prompt=login`
}),
Hi,
My solution (I am using Microsoft Azure Active Directory and it requires a separate call to logout of the AD):
Create api route api/auth/logout.js :
export default function handler(req, res) {
res.redirect(https://login.microsoftonline.com/common/oauth2/logout);
}
Then on my logout button I used the optional callback option:
<button onClick={() => signOut({ callbackUrl: `http://localhost:3000/api/auth/logout` })}>Sign Out</button>
It clears my token, then logs me out of the AAD.
Hey @iaincollins 馃憢, we are happily using NextAuth.js, but now we are finding ourselves to have the same issue as described in this thread. Using prompt=consent or promp=login is not an option for us, because we also need to invalidate the access token within the provider when signing out. So this is a big +1 for implementing the OpenID Connect Logout flow and we would be grateful for any hint where to start for a possible workaround. 馃檹
Hi,
My solution (I am using Microsoft Azure Active Directory and it requires a separate call to logout of the AD):Create api route
api/auth/logout.js:export default function handler(req, res) { res.redirect(https://login.microsoftonline.com/common/oauth2/logout); }Then on my logout button I used the optional callback option:
<button onClick={() => signOut({ callbackUrl: `http://localhost:3000/api/auth/logout` })}>Sign Out</button>It clears my token, then logs me out of the AAD.
For me this works very well.
This is the code i use for Auth0.
export default function handler(req, res) {
const returnTo = encodeURI("http://localhost:3000/");
res.redirect(`https://${process.env.AUTH0_DOMAIN}/v2/logout?client_id=${process.env.AUTH0_CLIENT_ID}&returnTo=${returnTo}`);
}
If you use Auth0 with third-party identity providers, you need to additionally add the federated flag as described here:
https://auth0.com/docs/api/authentication#logout
Log Users Out of Identity Providers
export default function handler(req, res) {
const returnTo = encodeURI('http://localhost:3000/');
res.redirect(
`https://${process.env.AUTH)_DOMAIN}/v2/logout?federated&returnTo=${returnTo}`
);
}
Most helpful comment
I solved this for Auth0 by setting the authorizationUrl's
promptparameter tologinwhich always shows the authentication page as described here (These are the docs for the new universal login experience but it also works for classic).Maybe this should be added as a tip to https://github.com/nextauthjs/next-auth/blob/main/www/docs/providers/auth0.md...?
After reading https://github.com/nextauthjs/next-auth/blob/main/www/docs/configuration/providers.md#oauth-provider-options which describes the
paramsproperty of the provider options as "Additional authorization URL parameters" I initially thought I could addprompt: 'login'there but that didn't work. What is that object used for?