Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to setup NEXTAUTH_URL for preview deployments? #497

Closed
1 of 5 tasks
ghoshnirmalya opened this issue Jul 28, 2020 · 35 comments
Closed
1 of 5 tasks

How to setup NEXTAUTH_URL for preview deployments? #497

ghoshnirmalya opened this issue Jul 28, 2020 · 35 comments
Labels
question Ask how to do something or how something works

Comments

@ghoshnirmalya
Copy link
Contributor

Vercel has the option to preview deployments of your pull requests before merging them. As a result, setting NEXTAUTH_URL would be tricky as the deployment url of a preview pull request might be different from the production url.

Your question
Is it possible to set the value of NEXTAUTH_URL dynamically? Also, why is this environment variable necessary to be set?

  • Found the documentation helpful
  • Found documentation but was incomplete
  • Could not find relevant documentation
  • Found the example project helpful
  • Did not find the example project helpful
@ghoshnirmalya ghoshnirmalya added the question Ask how to do something or how something works label Jul 28, 2020
@iaincollins
Copy link
Member

iaincollins commented Jul 28, 2020

Great question!

There are multiple contributing reasons as to why this needs to be set - and why it is an environment variable in v3.

API routes and Server Side Rendered functions (e.g. getServerSideProps and getInitialProps) need to know the site URL as they make a request back to the server - passing though the session token in the request object - to determine if a user is signed in.

This allows API routes and Server Side Rendered Pages to be lightweight and not have to pull in all the database code and other logic, which stays in the authentication route. Of course, using JSON Web Tokens sessions and the getToken helper is even faster as you can just verify the token without having to make a network call.

In v2 the site name and base path were options on NextAuth.js configuration, and this was passed to API routes and Server Side Pages using a Secure server side only configuration cookie. This has some security challenges, even a secure, server only cookie and was problematic in practice.

It is especially problematic in development mode or when rendering Server Side Pages. On first hit of a new deploy (a particular problem on local development instances) the server rendered page would not have had access to the cookie yet and so wouldn't know how to contact the server. Even requesting the page was enough for it to see and grab the value from the cookie for later reuse (as even Serverless functions are memory resident, e.g. for ~2 hours on AWS Lambda) but it was still an edge case there was no other obvious solution for.

It's possible to grab the host name from the req object, but this isn't a great solution as it has security problems; anyone can spoof the host header and exploit that (e.g. in a DDoS attack against another host).

Another consideration is that the hostnames in callback URLs for most OAuth providers need to exactly match the specified domains with the OAuth provider. In the vast majority of cases you can't use a wildcard with an OAuth provider either; you have to explicitly configure each Full Qualified Domain Name (e.g. example.com, www.example.com) so attempting to auto-discover it it doesn't work for a lot of folks in practice (security issues aside), as it depends on which URL the user has gone to.

So, it's an environment variable, which has the added benefit of being available to all pages and routes in an application, so works great for other API routes and for Server Side Pages. The environment variable also lets you specify a custom base path on it too, so it takes care of that problem as well.

In the case of Vercel, it actually reads in the instance name of VERCEL_URL as a fallback if NEXTAUTH_URL is not set (and, as that has no protocol, assumes HTTPS, which it always is on Vercel). If neither environment variable is set it assumes http://localhost:3000 for the hostname. If no base path for the auth routes is specified, it uses /api/auth as the default. This makes it really easy for folks to get started and try things out.

The VERCEL_URL property is an instance name though, and usually not what people are expecting to use as the URL in callbacks though, so it's of limited use right now - great for Email Provider or Credentials Provider (it's a valid hostname for the site to callback to), but doesn't work for OAuth as if you are using an OAuth provider (Google, Facebook, Twitter, etc) in almost all cases you will still need to explicitly allow the hostname of the test instance to be allowed. If you are using something like your own Open ID service then you could configure it to allow subdomains, but that's a bit of an exception.

I've had a chat with the Vercel folks about this and how it would be really nice if a user could define a 'default domain' for a site and use that for VERCEL_URL (or another, similar variable). That way it wouldn't need to be specified for production instances at least. They seem quite interested in this idea as it also address an issue they have, but I don't know if/when that would be.

However, even with that, there is still the issue for OAuth providers that they mostly (overwhelmingly) don't let you specify wildcard domains for valid callback URLs.

For test instances on Vercel, one option to get round this is to enable an Email provider or a Credentials Provider with hard coded credentials, only on Pull Request environments (e.g. if NEXTAUTH_URL isn't set) so they can still sign in, even if it's not the typical auth flow.

@ghoshnirmalya
Copy link
Contributor Author

@iaincollins Thank you for your detailed and quick reply.

I've removed NEXTAUTH_URL from my list of environment variables and used VERCEL_URL which is populated by the System variables in Vercel. However, when click on the "Sign In" button on this page, the following happens:

  1. I get redirected to this page which is correct.
  2. When I type my email address in the input box, I get redirected to this page. You can see that the url changes based on some environment variable (I'm not sure about which environment variable).
  3. Then, after I confirm my email address, I get redirected to this page with the following message:
Try signing with a different account.

Screenshot 2020-07-28 at 5 50 00 PM

I'm not getting any error related to my code. However, the logs are present in the screenshot above.

Any idea if this could happen because of the environment variables?

@iaincollins
Copy link
Member

Hmm, I'm not sure what's causing this - this should work!

Just to confirm the the second URL (after submitting an email address), e.g. https://nextjs-hasura-boilerplate-luzxmiugl.vercel.app, is the VERCEL_URL. It looks odd as it's always the auto-generated instance name, even if you have a domain configured.

The URL in the address bar changes when you submit because the form always uses the canonical callback URL for a provider (including email) and is always taken from the server config to ensure it's "correct"; and in this case because there is no NEXTAUTH_URL, is the VERCEL_URL. While it looks odd, that is all fine and should work.

I had a go at signing in myself saw the same behaviour, the email works fine but for some reason it can't sign me in!

That's really unusual.

That's the sort of thing I would expect to see if there is a problem with the database, but the email provider uses a database so I don't know why this his happening. I assume you have upgraded to 3.0.1 already, given you were the one who spotted the bug with that. :-)

Can I ask what sort of database you are using so I can see if I can replicate the issue?

PS: The example site uses DATABASE_URL=sqlite://localhost/:memory:?synchronize=true for an in memory SQLite database. While that's not suitable for production (only works if you have 1 x Lambda instance and Lambda instances are reset ~2 hours or more often) it's quite handy for test instances.

@ghoshnirmalya
Copy link
Contributor Author

I'm using Postgres on Heroku (free Hobby tier).

@ghoshnirmalya
Copy link
Contributor Author

@iaincollins I figured out the issue that was happening in my case. It was because I was signing my jwt with a secret. This thread/comment helped me with it.

@ghoshnirmalya
Copy link
Contributor Author

@iaincollins Also, I'm doing the following:

  1. Setting NEXTAUTH_URL for production deployments so that the providers callback redirects me to my canonical url.
  2. Setting VERCEL_URL for preview deployments so that I get redirected to the deployment url after logging in.

@iaincollins
Copy link
Member

I figured out the issue that was happening in my case. It was because I was signing my jwt with a secret. This thread/comment helped me with it.

Thanks for the update! That makes sense and is good to know.

We do the same thing for the private key on the Apple provider as how newlines get transformed in ENV VARs is pesky.

Based on your experience, happy to take any recommendations about error handling (either on the console or in API responses) that would make debugging this easier. I know there are potential areas for improvement there.

@francofantini
Copy link

@iaincollins thanks for the thorough explanation. I think you should include this in the documentation:

In the case of Vercel, it actually reads in the instance name of VERCEL_URL as a fallback if NEXTAUTH_URL is not set (and, as that has no protocol, assumes HTTPS, which it always is on Vercel). If neither environment variable is set it assumes http://localhost:3000 for the hostname. If no base path for the auth routes is specified, it uses /api/auth as the default. This makes it really easy for folks to get started and try things out.

Thanks!

@DeBraid
Copy link

DeBraid commented Oct 5, 2020

@ghoshnirmalya @iaincollins

Best I can tell VERCEL_URL is dynamic, and thus cannot be leveraged with most OAuth providers (like Google, in my case). What am I missing here?

When I follow this:

@iaincollins Also, I'm doing the following:

  1. Setting NEXTAUTH_URL for production deployments so that the providers callback redirects me to my canonical url.
  2. Setting VERCEL_URL for preview deployments so that I get redirected to the deployment url after logging in.

I get VERCEL_URLs that look like this:

foo.username.vercel.app
foo-git-staging.username.vercel.app
foo-5c5m1a3ef.vercel.app
foo-c135l33jd.vercel.app
foo-p2fxqw7m1.vercel.app
foo-o1s7js5is.vercel.app
...

My goal is to be able to test Auth on the previews, but that doesn't appear feasible at the moment?

@PaulKushch
Copy link

PaulKushch commented Oct 27, 2020

@iaincollins Where should one set NEXTAUTH_URL if not deploying to vercel? I use serverless next.js component (i.e. deploying to AWS Lambda@Edge & Cloudfront). Is it enough to set NEXTAUTH_URL in env.local file?
Best Regards

@breytex
Copy link

breytex commented Oct 31, 2020

+1 for this issue.
We are trying to set up oauth with Microsoft azure, and this requires to set up a safelist with all the known hosts of our app.
Our solution is to create multiple environments as branches and use the fixed names of the vercel branch deployments as callback URLs (set up in azure for the oauth app).

However, since VERCEL_URL injects the instance URLs instead of the fixed names, the redirect goes back to foo-5c5m1a3ef.vercel.app instead of foo-git-staging.username.vercel.app (which is safelisted in azure).

Any idea on how to solve that?

@lukeburns
Copy link

lukeburns commented Jan 25, 2021

For anyone else looking for workarounds...

If you need different NEXTAUTH_URLs for different branch deployments like I did, you can use next-branch-env to expose the env vars

NEXTAUTH_URL=https://myapp.com # production branch
STAGING_NEXTAUTH_URL=https://staging.myapp.com # preview branch
DEV_NEXT_NEXTAUTH_URL=https://dev.myapp.com # preview branch

as NEXTAUTH_URL on their respective branches. This happens at build time, rather than at runtime, so correct me if I'm wrong, but I don't see any new security concerns. VERCEL_URL did not work for us, because it does not expose our custom domain used for deployments.

Alternatively, you can set a global "root" site host (in Vercel Environment Variables):

ROOT_HOST=myapp.com

and programmatically (in your next.config.js file) define NEXTAUTH_URL based on the host and branch:

// next.config.js
const withBranchEnv = require('next-branch-env')({ expose: 'BRANCH' })
process.env.NEXTAUTH_URL = `https://${process.env.BRANCH}.${process.env.ROOT_HOST}`
module.exports = withBranchEnv(/* config */)

@iaincollins
Copy link
Member

iaincollins commented Jan 26, 2021

Thanks @lukeburns, that's really interesting and I'm sure helpful for folks!

@breytex Sorry we don't have a better answer yet, but is on the radar.

@PaulKushch

@iaincollins Where should one set NEXTAUTH_URL if not deploying to vercel? I use serverless next.js component (i.e. deploying to AWS Lambda@Edge & Cloudfront). Is it enough to set NEXTAUTH_URL in env.local file?

Sorry this reply is late, but for anyone else coming to this, if using AWS Lambda, then in the Serverless config is fine (if using Serverless) or in the config page for the Lambda on AWS console (you should be able to set it once and have it persist).

You can also set env vars manually via Vercel/Heroku/AWS dashboard.

NB: AWS Lambda@Edge (as opposed to AWS Lambda) is a tricky platform to support. Folks have been using it successfully (and am happy to take PRs related to supporting it!) but it's not something we test against so you might bump into issues with it.

Using NextAuth.js with CloudFront is fine. Running inside a CloudFront Workers is currently supported (as they are not Node.js), but running behind a CloudFront Worker (e.g. which checks a JWT set by NextAuth.js to do access control) is a great way to control access to content.

@alex-cory
Copy link
Contributor

alex-cory commented Mar 18, 2021

I do this with my team by having them do preview deployments like this.
vc -e NEXTAUTH_URL=https://user-preview-url.vercel.app
Unfortunately it won't scale with a large team, but at least it works for now, but so far we've only needed this for social login and some webhook apis.
Which allows you to set the env vars individually per dev.

@jonlow
Copy link

jonlow commented May 19, 2021

For anyone trying to get nextauth working on vercel preview environments I got it working by following the secure cookie issue made by @cathykc above #1672 (comment)

Basically just:

  • omit the NEXTAUTH_URL env variable from previews
  • make sure the secureCookie option in getToken returns true for preview urls

image

@ian
Copy link

ian commented Jul 27, 2021

It would be really helpful if url was a parameter that could be passed in to NextAuthOptions. That way we could set it to whatever we wanted.

@kettanaito
Copy link

How does setting a different/dynamic NEXTAUTH_URL help if GitHub fails any callback redirects if their destination differs from the "Callback URL" in the OAuth app's settings?

Can somebody please post a full working example of Next Auth support in Vercel preview deployments?

@balazsorban44
Copy link
Member

a summary on authentication in preview environments:

https://github.com/nextauthjs/docs/issues/19

@jonioni
Copy link

jonioni commented Nov 11, 2021

Some questions regarding Netlify preview deployments: #3176

@nemanjam
Copy link

nemanjam commented Jan 4, 2022

I am not clear if NEXTAUTH_URL should be set in build time for production or I can leave it undefined on build and set it just in runtime? Docs is not clear about this and it's very important.

@balazsorban44
Copy link
Member

On most platforms, you should ALWAYS set NEXTAUTH_URL. On Vercel, we try to detect the domain, which seem to be currently broken, and is tracked here: #3419

@moljac024
Copy link

Is next-auth reading that environment variable during build time or run time? We strive to have all our systems obey the 12-factor app rules (https://12factor.net/) and one of the big ones is being able to build once and run in multiple different configurations/environments.

Is next-auth compatible with that approach?

@gyurobenjamin
Copy link

Was this fixed since that, or is this still using build time env vars?

@yourcasualdev
Copy link

yourcasualdev commented Dec 22, 2022

Another issue is VERCEL_URL does not match the actual URL on previous deployments. Sometimes it fits sometimes it doesn't. And for this, I can't make a decent test environment for NextAuth.js
resim

@yourcasualdev
Copy link

Is next-auth reading that environment variable during build time or run time? We strive to have all our systems obey the 12-factor app rules (https://12factor.net/) and one of the big ones is being able to build once and run in multiple different configurations/environments.

Is next-auth compatible with that approach?

It reads variables at build time not run time. If you manually add the correct URL to env it'll not affect until you rebuild it.

@octavioamu
Copy link

not sure why this is closed but if there is a real solution about this issue should be better explained on the docs
https://next-auth.js.org/getting-started/example
image

Then on deployment page https://next-auth.js.org/deployment seems is saying exactly the opposite.
image

@aakash14goplani
Copy link

a summary on authentication in preview environments:

https://github.com/nextauthjs/docs/issues/19

@balazsorban44 - I would like to give it a read but this link is broken, can you please share the updated one? Thanks!

@ephraimduncan
Copy link
Contributor

@balazsorban44 Any update on the link?

@aakash14goplani
Copy link

My goal is to be able to test Auth on the previews, but that doesn't appear feasible at the moment?

@DeBraid - I am in similar situation now, were you able to solve this problem?

@aakash14goplani
Copy link

However, since VERCEL_URL injects the instance URLs instead of the fixed names, the redirect goes back to foo-5c5m1a3ef.vercel.app instead of foo-git-staging.username.vercel.app (which is safelisted in azure).

Any idea on how to solve that?

@breytex - I am in similar situation now, were you able to solve this problem?

@jcohenho
Copy link

For test instances on Vercel, one option to get round this is to enable an Email provider or a Credentials Provider with hard coded credentials, only on Pull Request environments (e.g. if NEXTAUTH_URL isn't set) so they can still sign in, even if it's not the typical auth flow.

@iaincollins Can you elaborate on this approach? How can we fake auth for a signed in user tied to a real record in the preview app DB?

@mohsen1
Copy link

mohsen1 commented Nov 27, 2023

One idea: NextAuth can encode the initial URL (preview URL) in the OAuth state and do another redirect after auth is successful with the production instance (after coming back from the provider to the production instance) to do another redirect and set-cookie for the initial URL and get user back where they started.

@stephenasuncionDEV
Copy link

getServerSession returns null for some reason, I'm using Next pages with trpc, and calling getServerSession inside trpc's createContext

@aakash14goplani
Copy link

For people from SvelteKit eco-system, I have written a blog on how we can achieve the same using fake identity server. Do give it a read!

@GoulartNogueira
Copy link

GoulartNogueira commented Aug 2, 2024

I'm using Next-Auth and this solved for me:

  1. Add NEXTAUTH_URL to development environment.
  2. Pull the change to .env
  3. Rebuild 🎉

Code for lazy people:

echo "http://localhost:3000" | vercel env add NEXTAUTH_URL development
vercel env pull
vercel build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Ask how to do something or how something works
Projects
None yet
Development

No branches or pull requests