Gate an internal site with oauth2-proxy
Put any internal tool, dashboard, or static site behind Scrydon SSO with oauth2-proxy — no application code changes — using Scrydon as the OIDC identity provider.
Have an internal tool, dashboard, wiki, or static site you want behind your
Scrydon login? You don't need to add authentication code to it. Put
oauth2-proxy in front of it
and point it at your Scrydon identity provider. oauth2-proxy runs the
OIDC login, sets its own session cookie on your site's domain, and only forwards
requests from signed-in users — restricted to whoever you allow (for example,
everyone with an @your-company.com email).
This is the standard "SSO for a site that has no SSO" pattern, and because
Scrydon is a full OIDC provider, the same approach works with any
OIDC-compatible proxy (Authelia, Pomerium, Traefik + oauth2-proxy, NGINX
auth_request, …). This guide uses oauth2-proxy.
oauth2-proxy sets its own cookie on your site's hostname, so it works no matter how Scrydon itself is hosted (subpath or subdomain routing) and no matter which subdomain your site lives on. Your site never sees the Scrydon session cookie directly.
Before you start
You need three things from Scrydon:
Register an org-scoped confidential client
Follow Register an OAuth client (Mini App). When you create it, set:
- Scope → Organization · SSO only. Your gateway only signs users in —
it doesn't call Scrydon APIs, so it needs no workspace and gets a single
org-wide client restricted to the identity scopes (
openid,profile,email). - Client Type → Confidential · client secret. oauth2-proxy runs
server-side and authenticates to the token endpoint with a
client_secret. - Redirect URI →
https://<your-site>/oauth2/callback(oauth2-proxy's callback path). Example:https://docs.internal.example.com/oauth2/callback.
You'll receive a client ID and a client secret.
The client secret is shown exactly once, right after registration — copy it immediately. Scrydon stores only a hash, so it cannot be retrieved later. If you lose it, use Rotate in the app's detail panel to mint a new one (the old secret stops working the moment you rotate).
Copy your Discovery URL
Open Settings → Platform → Identity and copy the OIDC Discovery URL. It
looks like https://<your-auth-host>/api/auth/.well-known/openid-configuration.
oauth2-proxy only needs the issuer — that's the same URL without the
/.well-known/openid-configuration suffix, e.g. https://<your-auth-host>/api/auth.
Always copy the host from the Identity tab — it is tenant-specific. Don't guess it.
Generate a cookie secret
oauth2-proxy signs its own cookie with a secret that must be exactly 16, 24, or 32 bytes:
openssl rand -base64 32 | head -c 32; echoConfigure oauth2-proxy
oauth2-proxy is configured entirely through flags or OAUTH2_PROXY_*
environment variables. The minimal OIDC setup:
oauth2-proxy \
--provider=oidc \
--oidc-issuer-url="https://<your-auth-host>/api/auth" \
--client-id="<your-client-id>" \
--client-secret="<your-client-secret>" \
--redirect-url="https://<your-site>/oauth2/callback" \
--scope="openid email profile" \
--email-domain="your-company.com" \
--cookie-secret="<cookie-secret>" \
--cookie-secure=true \
--upstream="http://127.0.0.1:8080/" \
--http-address="0.0.0.0:4180" \
--reverse-proxy=true \
--skip-provider-button=trueKey options:
| Option | Why |
|---|---|
--oidc-issuer-url | The issuer from your Discovery URL. oauth2-proxy fetches everything else automatically. |
--redirect-url | Must exactly match the Mini App Redirect URI. |
--email-domain | Allow-list. Repeat the flag (or comma-separate) for several domains; * allows any signed-in Scrydon user. |
--upstream | Your actual site/tool. oauth2-proxy reverse-proxies authenticated traffic here. |
--reverse-proxy=true | Set when running behind your own ingress/load balancer so X-Forwarded-* is trusted. |
--skip-provider-button=true | Go straight to the Scrydon login instead of an intermediate "Sign in with…" page. |
To restrict to specific people rather than a whole domain, drop
--email-domain and use --authenticated-emails-file=/path/to/emails.txt
(one address per line).
Deploy it
Docker Compose
services:
my-internal-site:
image: my-internal-site:latest
# no auth code needed in your app
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.7.1
command:
- --provider=oidc
- --oidc-issuer-url=https://<your-auth-host>/api/auth
- --client-id=<your-client-id>
- --client-secret=<your-client-secret>
- --redirect-url=https://docs.internal.example.com/oauth2/callback
- --scope=openid email profile
- --email-domain=your-company.com
- --cookie-secret=<cookie-secret>
- --cookie-secure=true
- --http-address=0.0.0.0:4180
- --reverse-proxy=true
- --skip-provider-button=true
- --upstream=http://my-internal-site:80/
ports:
- "4180:4180"Point your TLS terminator / DNS for docs.internal.example.com at the
oauth2-proxy container's :4180.
Kubernetes (reverse-proxy in front of a Service)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-site-oauth2-proxy
spec:
replicas: 1
selector:
matchLabels: { app: my-site-oauth2-proxy }
template:
metadata:
labels: { app: my-site-oauth2-proxy }
spec:
containers:
- name: oauth2-proxy
image: quay.io/oauth2-proxy/oauth2-proxy:v7.7.1
args:
- --provider=oidc
- --oidc-issuer-url=https://<your-auth-host>/api/auth
- --redirect-url=https://docs.internal.example.com/oauth2/callback
- --scope=openid email profile
- --email-domain=your-company.com
- --upstream=http://my-site.default.svc.cluster.local:80/
- --http-address=0.0.0.0:4180
- --cookie-secure=true
- --reverse-proxy=true
- --skip-provider-button=true
env:
- name: OAUTH2_PROXY_CLIENT_ID
valueFrom: { secretKeyRef: { name: my-site-sso, key: client-id } }
- name: OAUTH2_PROXY_CLIENT_SECRET
valueFrom: { secretKeyRef: { name: my-site-sso, key: client-secret } }
- name: OAUTH2_PROXY_COOKIE_SECRET
valueFrom: { secretKeyRef: { name: my-site-sso, key: cookie-secret } }
ports:
- containerPort: 4180
---
apiVersion: v1
kind: Service
metadata:
name: my-site-oauth2-proxy
spec:
selector: { app: my-site-oauth2-proxy }
ports:
- port: 4180
targetPort: 4180Then route your Ingress for docs.internal.example.com to the
my-site-oauth2-proxy Service on port 4180 (instead of straight to your app).
oauth2-proxy owns the /oauth2/* paths and proxies everything else to your
upstream once the user is authenticated.
Verify
- Open
https://docs.internal.example.com/in a fresh browser session. - You should be redirected to your Scrydon login.
- Sign in with an allowed account → you land on your site.
- An account outside the allow-list is rejected after login.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
invalid_client at the login screen | The client ID/secret don't match a registered app, or the secret was rotated since you configured the proxy. |
| Redirects back to login in a loop | --cookie-secure=true but the site is served over plain HTTP, or TLS isn't terminated in front of oauth2-proxy. Serve over HTTPS. |
redirect_uri mismatch error | --redirect-url must exactly equal the Mini App Redirect URI, including scheme and the /oauth2/callback path. |
| Rejected right after login | The account's email isn't in --email-domain / the allowed-emails file. |
cookie secret … must be 16, 24, or 32 bytes | Regenerate the cookie secret to exactly 32 bytes. |
| "email not verified" rejection | The account's email isn't verified. Verify it, or (lower assurance) add --insecure-oidc-allow-unverified-email=true. |