next-auth
next-auth copied to clipboard
NEXTAUTH_URL_INTERNAL variable does not work with keycloak
Provider type
Keycloak
Environment
System: OS: Windows 10 10.0.19043 CPU: (8) x64 Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz Memory: 3.30 GB / 15.76 GB Binaries: Node: 16.13.1 - C:\laragon\bin\nodejs\node-v16.13.1\node.EXE Yarn: 1.22.11 - ~\AppData\Roaming\npm\yarn.CMD npm: 8.3.2 - C:\laragon\bin\nodejs\node-v16.13.1\npm.CMD Browsers: Edge: Spartan (44.19041.1266.0), Chromium (98.0.1108.55) Internet Explorer: 11.0.19041.1202 npmPackages: next: 12.0.7 => 12.0.7 next-auth: ^4.0.6 => 4.0.6 react: 17.0.2 => 17.0.2
Reproduction URL
https://github.com/nextauthjs/next-auth-example
Describe the issue
I am using Next-auth with keycloak and docker-compose.
Everything works fine on my local computer, but when I use docker-compose i get this error:
arcade-iori | [next-auth][error][GET_AUTHORIZATION_URL_ERROR]
arcade-iori | https://next-auth.js.org/errors#get_authorization_url_error connect ECONNREFUSED 127.0.0.1:80 {
arcade-iori | message: 'connect ECONNREFUSED 127.0.0.1:80',
arcade-iori | stack: 'Error: connect ECONNREFUSED 127.0.0.1:80\n' +
arcade-iori | ' at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1157:16)',
arcade-iori | name: 'Error'
arcade-iori | }
arcade-iori | [next-auth][error][SIGNIN_OAUTH_ERROR]
arcade-iori | https://next-auth.js.org/errors#signin_oauth_error connect ECONNREFUSED 127.0.0.1:80 {
arcade-iori | error: {
arcade-iori | message: 'connect ECONNREFUSED 127.0.0.1:80',
arcade-iori | stack: 'Error: connect ECONNREFUSED 127.0.0.1:80\n' +
arcade-iori | ' at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1157:16)',
arcade-iori | name: 'Error'
arcade-iori | },
arcade-iori | provider: {
arcade-iori | id: 'keycloak',
arcade-iori | name: 'Keycloak',
arcade-iori | wellKnown: 'http://abianic.test/auth/realms/myrealm/.well-known/openid-configuration',
arcade-iori | type: 'oauth',
arcade-iori | authorization: { params: [Object] },
arcade-iori | checks: [ 'pkce', 'state' ],
arcade-iori | idToken: true,
arcade-iori | profile: [Function: profile],
arcade-iori | clientId: 'myclientnext',
arcade-iori | clientSecret: 'Pw6ffETQgR5VLeXKL3v5jIsTjkNyvvCA',
arcade-iori | issuer: 'http://abianic.test/auth/realms/myrealm',
arcade-iori | signinUrl: 'http://abianic.test/api/auth/signin/keycloak',
arcade-iori | callbackUrl: 'http://abianic.test/api/auth/callback/keycloak'
arcade-iori | },
arcade-iori | message: 'connect ECONNREFUSED 127.0.0.1:80'
arcade-iori | }
How to reproduce
This is the Next-auth config:
import NextAuth from "next-auth"
import KeycloakProvider from "next-auth/providers/keycloak";
export default NextAuth({
debug: true,
secret: process.env.SECRET,
site: process.env.NEXTAUTH_URL,
providers: [
KeycloakProvider({
clientId: 'myclientnext',
clientSecret: 'Pw6ffETQgR5VLeXKL3v5jIsTjkNyvvCA...',
issuer: 'http://abianic.test/auth/realms/myrealm',
authorizationUrl: "http://abianic.test/auth/realms/myrealm/protocol/openid-connect/auth",
accessTokenUrl: "http://abianic.test/auth/realms/myrealm/protocol/openid-connect/token",
profileUrl: "http://abianic.test/auth/realms/myrealm/protocol/openid-connect/userinfo",
})
],
})
This is my docker-compose.yml:
version: '3.7'
volumes:
keycloak_db_data:
driver: local
networks:
arcadenet:
driver: bridge
services:
keycloak-db:
image: postgres:11.2
container_name: arcade-keycloak-db
volumes:
- keycloak_db_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: arcadecloack
POSTGRES_USER: arcade
POSTGRES_PASSWORD: arcade
networks:
- arcadenet
keycloak:
image: quay.io/keycloak/keycloak:16.1.0
container_name: arcade-keycloak
environment:
DB_VENDOR: POSTGRES
DB_ADDR: arcade-keycloak-db
DB_DATABASE: arcadecloack
DB_USER: arcade
DB_SCHEMA: public
DB_PASSWORD: arcade
KEYCLOAK_USER: admin4
KEYCLOAK_PASSWORD: admin
PROXY_ADDRESS_FORWARDING: true
# Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
#JDBC_PARAMS: "ssl=true"
ports:
- 8080:8080
depends_on:
- keycloak-db
networks:
- arcadenet
iori:
stdin_open: true # docker run -i
tty: true # docker run -t
build:
context: ../iori/
dockerfile: Dockerfile
image: iori
container_name: arcade-iori
restart: always
ports:
- 3000:3000
volumes:
- '../iori/:/app'
- '/app/node_modules'
- '/app/.next'
environment:
- CHOKIDAR_USEPOLLING=true
networks:
- arcadenet
proxy:
image: nginx
container_name: arcade-proxy
restart: unless-stopped
ports:
- 80:80
volumes:
- ./default-proxy.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- arcadenet
depends_on:
- keycloak
- iori
the env.local file:
NEXTAUTH_URL=http://abianic.test/
NEXTAUTH_URL_INTERNAL=http://arcade-iori:3000/
NEXTAUTH_SECRET=asd
This is the default-proxy.conf:
server {
listen 80;
listen [::]:80;
server_name abianic.test;
location /keycloak/ {
proxy_pass http://arcade-keycloak:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /auth/ {
proxy_pass http://arcade-keycloak:8080/auth/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://arcade-iori:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# requests without trailing slash will be forwarded to include slash
location = /backend {
return 301 $scheme://$http_host$uri/$is_args$args;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
host file:
127.0.0.1 abianic.test
I think the problem is that if it's running in a Docker container then http://127.0.0.1:80 from the perspective of the Docker container is diferebt on each container, but I don't have "localhost/127.0.0.1" configured anywhere.
Expected behavior
verything works fine when I run the Next.js project on my local computer (http://localhost:3000/), but when I use docker-compose to run the project in a container I get the error
So NextAuth.js / the Next.js app is running inside a container as well? And it's tryign to connect to abianic.test
from the looks of your error messages, right?
abianic.test
seems to be mapped to 127.0.0.1
inside that container named arcade-iori
. Meanign its trying to connect to port 80 inside its own container, where nothign is probably listening.
You'll have to set in the NextAuth.js config the keycloak URLs to something that the next.js container can reach. For example, the well-known URL should be something like this I think: http://arcade-keycloak:8080/auth/realms/myrealm/.well-known/openid-configuration
So NextAuth.js / the Next.js app is running inside a container as well? And it's tryign to connect to
abianic.test
from the looks of your error messages, right?
abianic.test
seems to be mapped to127.0.0.1
inside that container namedarcade-iori
. Meanign its trying to connect to port 80 inside its own container, where nothign is probably listening.You'll have to set in the NextAuth.js config the keycloak URLs to something that the next.js container can reach. For example, the well-known URL should be something like this I think:
http://arcade-keycloak:8080/auth/realms/myrealm/.well-known/openid-configuration
thanks for reply @ndom91, after set the wellKnown parameter in the NextAuth.js config file.
export default NextAuth({
debug: true,
secret: process.env.NEXTAUTH_SECRET,
site: process.env.NEXTAUTH_URL,
providers: [
KeycloakProvider({
clientId: 'myclientnext',
clientSecret: 'Pw6ffETQgR5VLeXKL3v5jIsTjkNyvvCA',
issuer: 'http://abianic.test/auth/realms/myrealm',
authorizationUrl: "http://abianic.test/auth/realms/myrealm/protocol/openid-connect/auth",
accessTokenUrl: "http://abianic.test/auth/realms/myrealm/protocol/openid-connect/token",
profileUrl: "http://abianic.test/auth/realms/myrealm/protocol/openid-connect/userinfo",
wellKnown: "http://arcade-keycloak:8080/auth/realms/myrealm/.well-known/openid-configuration",
})
],
})
the browser tries to redirect to the url:
http://arcade-keycloak:8080/auth/realms/myrealm/protocol/openid-connect/auth?client_id=myclientnext&scope=openid%20email%20profile&response_type=code&redirect_uri=http%3A%2F%2Fabianic.test%2Fapi%2Fauth% 2Fcallback%2Fkeycloak&state=RIctRwFCJ_QDggWogC21x95AqxWA1xOzo1UUQc1VUt0&code_challenge=N3I6UVWezrhw16mt-UtugZDbDf8zf1kA2N1eYeT0_-8&code_challenge_method=S256
causing an error because internal Docker paths cannot be accessed from the browser
Ah okay yeah my bad, I misunderstood the setup a bit.
Where does abianic.test
come from exactly? Shouldn't those all be http://project.test/auth/..
or whatever your proxy container is setup as?
Ah okay yeah my bad, I misunderstood the setup a bit.
Where does
abianic.test
come from exactly? Shouldn't those all behttp://project.test/auth/..
or whatever your proxy container is setup as?
http://project.test => http://abianic.test
My bad, I made some changes and forgot to put the updated messages with the correct host.
Hey! Do you have any news on this topic? I'm currently experimenting with the same issue with docker
Hey! Do you have any news on this topic? I'm currently experimenting with the same issue with docker
my solution was to put a new entry in host file:
127.0.0.1 abianic.test
127.0.0.1 arcade-proxy
And point the [...nextauth].js file to the url with the keycloak container name:
import NextAuth from "next-auth"
import KeycloakProvider from "next-auth/providers/keycloak";
export default NextAuth({
debug: true,
secret: process.env.NEXTAUTH_SECRET,
site: process.env.NEXTAUTH_URL,
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_ID,
clientSecret: process.env.KEYCLOAK_SECRET,
issuer: process.env.KEYCLOAK_ISSUER,
authorizationUrl: "http://arcade-proxy/auth/realms/myrealm/protocol/openid-connect/auth",
accessTokenUrl: "http://arcade-proxy/auth/realms/myrealm/protocol/openid-connect/token",
profileUrl: "http://arcade-proxy/auth/realms/myrealm/protocol/openid-connect/userinfo",
wellKnown: "http://arcade-proxy/auth/realms/myrealm/.well-known/openid-configuration",
})
],
})
my solution was to put a new entry in host file:
Thank you very much, kind of a workaround for the moment but it'll do the job!
Actually having the same issue "connect ECONNREFUSED 127.0.0.1:8080" but my keycloak isn't deployed in a docker container. Has anyone found a working solution?
I think this should still be fixed at some point. Not being able to test OAuth with a local Docker deployment of every container is really annoying. Especially when you are used to running everything in containers and don't want to get everything installed.
I think it would be nice to allow (in the OAuth Interface itself) a parameter that works analogous to NEXTAUTH_URL_INTERNAL. So just some value that is used to parse the origin (scheme, domain, and most importantly port!), which is then used in every server side request.
If there are any downsides, please do let me know.
Yeah so the main issue here is that 127.0.0.1
is referring to different things from the perspective of each container / the host, right?
Some possible solutions / workarounds include:
- If you're using docker on mac, you can always refer to the host with the hostname
host.docker.internal
- You could use host networking (i.e. the
--network host
flag) - You could set some additional hostnames in your
/etc/hosts
file, as has already been suggested here - Docker containers, amongst one another in a
docker-compose
setup, automatically get/etc/hosts
entries for each other container based on the continer names. So like a hypotheticalapp
container automatically has a hostname setup for thedb
container (for example), so to link to postgres instance running in thedb
container, you could just point it atdb:5432
.
I'll close this issue for now as we seem to have identified the root cause of the issue and others have provided some solutions. It's not really a next-auth
code related issue, but rather a configuration error related to container networking.
Actually having the same issue "connect ECONNREFUSED 127.0.0.1:8080" but my keycloak isn't deployed in a docker container. Has anyone found a working solution?
Your Next.js application and Keycloak are deployed on the same server? Are you sure theres something listening on port 8080
? You can check with sudo netstat -tlpn
on most linux distros to show all open tcp ports in a list.
There is no way to change a port. So I would still like for there being a better way. The /etc/hosts
file can only do domains. But the server is hosted in docker at 8080
. and I have to map it to somewhere else.
Then your only option is to use a reverse proxy like nginx. That would, for example. take incoming requests on localhost:1234
and forward them on to localhost:8080
, essentially making the service available under port 1234
as well.
Docs: https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ Howto: https://gist.github.com/soheilhy/8b94347ff8336d971ad0
Are you sure theres no keycloak config to change the port it listens on though? That seems to be a pretty standard option.
Additionally, if you're running keycloak in a container you can use docker to remap the port it makes the service running in the container available on on the outside, for example with the docker flag -p 1234:8080
to remap 8080
internally in the container to 1234
on the outside.
Hey @crisgarlez, I'm at the exact same point now. Inside the container it does not work. Proxy is setup and everything is working fine, server-side the requests somehow still end up in "127.0.0.1" and not the proxyed url, therefore it fails because it's happening inside the container, as was described already above.
I did not quite understand your solution, what exactly is the "arcade-proxy" and where did you use the keycloak container name as domain name?
Thanks a lot for any support!
Hey @crisgarlez, I'm at the exact same point now. Inside the container it does not work. Proxy is setup and everything is working fine, server-side the requests somehow still end up in "127.0.0.1" and not the proxyed url, therefore it fails because it's happening inside the container, as was described already above.
I did not quite understand your solution, what exactly is the "arcade-proxy" and where did you use the keycloak container name as domain name?
Thanks a lot for any support!
Hey @wireless25 "arcade-proxy" is the name for my Nginx Proxy container, if you look the "docker-compose.yml" file you find a service with the name "proxy" and "container_name: arcade-proxy". Inside of the NextJs container, we can point to "http://arcade-proxy/auth/" this means tha you are pointing to the Nginx Proxy, then the proxi redirects the request to "auth" to -> http://arcade-keycloak:8080/auth/ using the "location /auth/" configured in the default-proxy.conf.
But we have a problem, if you point to the "http://arcade-proxy/auth/" outside of the docker container, does not exists. Thats the reason beacause of we need to put the 127.0.0.1 arcade-proxy
line in the host file, to access to the proxy with the url arcade-proxy
inside or outside the docker container.
Hey @crisgarlez, I'm at the exact same point now. Inside the container it does not work. Proxy is setup and everything is working fine, server-side the requests somehow still end up in "127.0.0.1" and not the proxyed url, therefore it fails because it's happening inside the container, as was described already above. I did not quite understand your solution, what exactly is the "arcade-proxy" and where did you use the keycloak container name as domain name? Thanks a lot for any support!
Hey @wireless25 "arcade-proxy" is the name for my Nginx Proxy container, if you look the "docker-compose.yml" file you find a service with the name "proxy" and "container_name: arcade-proxy". Inside of the NextJs container, we can point to "http://arcade-proxy/auth/" this means tha you are pointing to the Nginx Proxy, then the proxi redirects the request to "auth" to -> http://arcade-keycloak:8080/auth/ using the "location /auth/" configured in the default-proxy.conf.
But we have a problem, if you point to the "http://arcade-proxy/auth/" outside of the docker container, does not exists. Thats the reason beacause of we need to put the
127.0.0.1 arcade-proxy
line in the host file, to access to the proxy with the urlarcade-proxy
inside or outside the docker container.
@crisgarlez Thank you very much for taking the time and explaining the solution in detail. This helps a lot and I will try to implement it in my project soon.
I notice the same problem, but none of the workaround are applicable. The point is that the browser can access the Keycloak server at the same base address as my application (eg.: https://127.0.0.1 ), but the server should point to a named container, with even a different protocol (eg.: http://mykeycloak; notice the http, instead of https). The NEXTAUTH_URL_INTERNAL variable seems just to be ignored.
Hey @crisgarlez, I'm at the exact same point now. Inside the container it does not work. Proxy is setup and everything is working fine, server-side the requests somehow still end up in "127.0.0.1" and not the proxyed url, therefore it fails because it's happening inside the container, as was described already above. I did not quite understand your solution, what exactly is the "arcade-proxy" and where did you use the keycloak container name as domain name? Thanks a lot for any support!
Hey @wireless25 "arcade-proxy" is the name for my Nginx Proxy container, if you look the "docker-compose.yml" file you find a service with the name "proxy" and "container_name: arcade-proxy". Inside of the NextJs container, we can point to "http://arcade-proxy/auth/" this means tha you are pointing to the Nginx Proxy, then the proxi redirects the request to "auth" to -> http://arcade-keycloak:8080/auth/ using the "location /auth/" configured in the default-proxy.conf.
But we have a problem, if you point to the "http://arcade-proxy/auth/" outside of the docker container, does not exists. Thats the reason beacause of we need to put the
127.0.0.1 arcade-proxy
line in the host file, to access to the proxy with the urlarcade-proxy
inside or outside the docker container.
Hi @crisgarlez Thanks for writing about this issue. But i have one question: You put the host file entry at your local machine, right? Because we need to redirect the client side http call outside of the container. My understanding is that this solution works for your own machine, but how would we fix this error in production? I want to redirect users to the right adress but keep getting the unresolved host name (e.g. http://arcade-keycloak)