Fix OIDC token exchange behind HTTPS reverse proxy (#162)

* Initial plan

* Fix OIDC callback URL construction for HTTPS reverse proxy

- Replace hardcoded http:// URL with OIDC_REDIRECT_URI from environment
- Build complete callback URL with query parameters for proper validation
- Fixes token exchange 401 errors when running behind HTTPS reverse proxy

Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>

* Update OIDC_REDIRECT_URI documentation to clarify full URL requirement

Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>

* fix: format oidc.ts to pass biome check

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>
Co-authored-by: Daniel Volz <mail@danielvolz.org>
This commit is contained in:
Copilot
2026-02-13 18:29:33 +01:00
committed by GitHub
parent 38f3533dd9
commit 0b0472f2f5
3 changed files with 16 additions and 10 deletions
+1 -1
View File
@@ -213,7 +213,7 @@ Generate secrets with: `openssl rand -hex 32`
| `OIDC_ISSUER_URL` | — | OIDC provider URL |
| `OIDC_CLIENT_ID` | — | Client ID from OIDC provider |
| `OIDC_CLIENT_SECRET` | — | Client secret from OIDC provider |
| `OIDC_REDIRECT_URI` | — | Callback URL |
| `OIDC_REDIRECT_URI` | — | Full callback URL (e.g., `https://your-domain.com/api/auth/oidc/callback`) |
| `OIDC_SCOPES` | `openid profile email` | Scopes to request |
| `OIDC_USERNAME_CLAIM` | `preferred_username` | Claim for username |
| `OIDC_AUTO_CREATE_USERS` | `true` | Auto-create users on first SSO login |
+6
View File
@@ -2243,6 +2243,7 @@
"resolved": "https://registry.npmjs.org/@libsql/client/-/client-0.10.0.tgz",
"integrity": "sha512-2ERn08T4XOVx34yBtUPq0RDjAdd9TJ5qNH/izugr208ml2F94mk92qC64kXyDVQINodWJvp3kAdq6P4zTtCZ7g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@libsql/core": "^0.10.0",
"@libsql/hrana-client": "^0.6.2",
@@ -4742,6 +4743,7 @@
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
@@ -5938,6 +5940,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -6699,6 +6702,7 @@
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
@@ -6762,6 +6766,7 @@
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -6837,6 +6842,7 @@
"integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vitest/expect": "4.0.16",
"@vitest/mocker": "4.0.16",
+9 -9
View File
@@ -144,17 +144,17 @@ export async function oidcRoutes(app: FastifyInstance) {
try {
const config = await getOIDCConfig();
const _redirectUri = env.OIDC_REDIRECT_URI!;
const redirectUri = env.OIDC_REDIRECT_URI!;
// Exchange code for tokens
const tokens = await client.authorizationCodeGrant(
config,
new URL(request.url, `http://${request.headers.host}`),
{
pkceCodeVerifier: storedVerifier.value,
expectedState: state,
}
);
// Build complete callback URL with query parameters for validation
const callbackUrl = new URL(redirectUri);
callbackUrl.search = new URLSearchParams(request.query as Record<string, string>).toString();
const tokens = await client.authorizationCodeGrant(config, callbackUrl, {
pkceCodeVerifier: storedVerifier.value,
expectedState: state,
});
// Get user info
const sub = tokens.claims()?.sub;