fix(auth): never set AUTH_URL to empty, and catch the case that broke - #24
Merged
Merged
Conversation
Production reported auth:true while every Auth.js route returned 500. Both
halves of that were my fault.
`AUTH_URL: ${AUTH_URL:-}` was the obvious way to make the variable optional in
compose. It sets it to the empty string, which is a set variable, and that is
strictly worse than an absent one in two ways at once: it shadows the default
the Dockerfile bakes in from NEXT_PUBLIC_APP_URL, and it stops @auth/core's
trustHost ??= !!(AUTH_URL ?? AUTH_TRUST_HOST ?? VERCEL ?? ...)
at the first term, because `??` falls through only on null/undefined and `!!""`
is false. trustHost:false makes assertConfig return UntrustedHost for every
request, which renders as "There was a problem with the server configuration" --
indistinguishable from a missing secret, which is where the debugging went.
It now defaults to NEXT_PUBLIC_APP_URL, so it stays overridable without ever
being blank.
The readiness check said this deployment was fine. A green light that is wrong
is worse than no light, because it teaches people to stop looking at it, so it
now encodes both faults it missed:
It mirrors the trustHost expression, including the `??` semantics, and
distinguishes "AUTH_URL is set but empty" from "AUTH_URL is not set" -- the
first is not a thing anyone guesses while debugging.
It treats a half-configured OAuth provider as fatal. The previous version
ignored the OAuth credentials, reasoning that a deployment with no Google app
still supports credentials and magic-link sign-in. That is true only when the
provider is absent entirely; an id without its secret makes Auth.js throw while
building the provider list, taking down every sign-in method including the ones
that need no provider at all.
`missing` becomes `problems`, since these are diagnoses rather than a list of
absent names. Still names and sentences only, never values -- /api/health is
public.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Production reported
"auth": truewhile every Auth.js route returned 500. Both halves of that were mine.The empty string
AUTH_URL: ${AUTH_URL:-}was the obvious way to make the variable optional in compose. It sets it to the empty string — a set variable — which is strictly worse than an absent one, in two ways at once:NEXT_PUBLIC_APP_URL.@auth/core's trust-host expression at the first term:??falls through only onnull/undefined.""stops the chain, and!!""isfalse. WithtrustHost: false,assertConfigreturnsUntrustedHostfor every request — rendered to the user as "There was a problem with the server configuration", which is indistinguishable from a missing secret. That is exactly where the debugging went.It now defaults to
NEXT_PUBLIC_APP_URL, so it stays overridable without ever being blank.The check that should have caught it
getAuthReadinesssaid the deployment was fine. A green light that is wrong is worse than no light — it teaches people to stop looking at it. It now encodes both faults it missed:Trusted host. It mirrors the
trustHostexpression including the??semantics, and distinguishes "AUTH_URL is set but empty" from "AUTH_URL is not set". The first is not something anyone guesses while debugging, so the message has to say it.Half-configured OAuth providers. The previous version deliberately ignored the OAuth credentials, reasoning that a deployment with no Google app still supports credentials and magic-link sign-in. That is true only when the provider is absent entirely. An id without its secret makes Auth.js throw while building the provider list, which takes down every sign-in method — including the ones that need no provider at all. So
id XOR secretis now fatal, while neither remains fine.missingbecomesproblems, since these are diagnoses rather than a list of absent names. Still names and sentences only, never values —/api/healthis public.Verification
tsc --noEmitclean, production build green.docker-compose.ymlparses;AUTH_URLresolves to${AUTH_URL:-$NEXT_PUBLIC_APP_URL}.Deploying
The compose change has to reach the VM — this is a
docker-compose.ymlfix, so a new image alone will not carry it. After redeploy,/api/auth/providersreturning the provider list instead of 500 is the confirmation.