diff --git a/Dockerfile b/Dockerfile index 8c7c11d..23e8b7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,9 @@ # Base runs as USER authorizer (uid 1000). For SQLite, ensure mounted /data is writable by that user. -FROM quay.io/authorizer/authorizer:2.3.0 +# Pinned to the 2.4.0 release candidate because it is the first published +# image with the current CLI flag surface (--url, --oauth2-1-strict, +# --enable-org-discovery, --disable-totp-login/-webauthn-mfa/-email-otp/ +# -sms-otp/-mfa). Re-pin to the stable 2.4.0 tag once it ships. +FROM quay.io/authorizer/authorizer:2.4.0-rc.18 # Override so CMD runs in a shell and env vars (e.g. for Render) are expanded. See base image comment. # Use exec-form CMD with a single string so /bin/sh -c gets one argument; shell-form CMD can be split and drop into a shell. ENTRYPOINT ["/bin/sh", "-c"] @@ -14,6 +18,7 @@ CMD ["exec ./authorizer \\\n\ --redis-url=\"${REDIS_URL}\" \\\n\ --jwt-type=\"${JWT_TYPE}\" \\\n\ --jwt-secret=\"${JWT_SECRET}\" \\\n\ + --encryption-key=\"${ENCRYPTION_KEY}\" \\\n\ --jwt-private-key=\"${JWT_PRIVATE_KEY}\" \\\n\ --jwt-public-key=\"${JWT_PUBLIC_KEY}\" \\\n\ --jwt-role-claim=\"${JWT_ROLE_CLAIM}\" \\\n\ @@ -28,6 +33,7 @@ CMD ["exec ./authorizer \\\n\ --allowed-origins=\"${ALLOWED_ORIGINS}\" \\\n\ --default-authorize-response-type=\"${DEFAULT_AUTHORIZE_RESPONSE_TYPE}\" \\\n\ --default-authorize-response-mode=\"${DEFAULT_AUTHORIZE_RESPONSE_MODE}\" \\\n\ + --oauth2-1-strict=\"${OAUTH2_1_STRICT:-false}\" \\\n\ --organization-name=\"${ORGANIZATION_NAME}\" \\\n\ --organization-logo=\"${ORGANIZATION_LOGO}\" \\\n\ --smtp-host=\"${SMTP_HOST}\" \\\n\ @@ -38,6 +44,7 @@ CMD ["exec ./authorizer \\\n\ --smtp-sender-name=\"${SENDER_NAME}\" \\\n\ --reset-password-url=\"${RESET_PASSWORD_URL}\" \\\n\ --backchannel-logout-uri=\"${BACKCHANNEL_LOGOUT_URI}\" \\\n\ + --url=\"${AUTHORIZER_URL}\" \\\n\ --env=\"${ENV}\" \\\n\ --host=\"${HOST:-0.0.0.0}\" \\\n\ --metrics-port=\"${METRICS_PORT:-8081}\" \\\n\ @@ -51,6 +58,7 @@ CMD ["exec ./authorizer \\\n\ --rate-limit-burst=\"${RATE_LIMIT_BURST:-20}\" \\\n\ --rate-limit-fail-closed=\"${RATE_LIMIT_FAIL_CLOSED:-false}\" \\\n\ --enable-login-page=\"${ENABLE_LOGIN_PAGE:-true}\" \\\n\ + --enable-org-discovery=\"${ENABLE_ORG_DISCOVERY:-false}\" \\\n\ --enable-playground=\"${ENABLE_PLAYGROUND:-true}\" \\\n\ --disable-admin-header-auth=\"${DISABLE_ADMIN_HEADER_AUTH:-true}\" \\\n\ --enable-graphql-introspection=\"${ENABLE_GRAPHQL_INTROSPECTION:-true}\" \\\n\ @@ -75,6 +83,7 @@ CMD ["exec ./authorizer \\\n\ --database-cert-key=\"${DATABASE_CERT_KEY}\" \\\n\ --fga-store=\"${FGA_STORE}\" \\\n\ --fga-store-url=\"${FGA_STORE_URL}\" \\\n\ + --fga-allow-unconstrained-agents=\"${FGA_ALLOW_UNCONSTRAINED_AGENTS:-false}\" \\\n\ --couchbase-bucket=\"${COUCHBASE_BUCKET}\" \\\n\ --couchbase-scope=\"${COUCHBASE_SCOPE}\" \\\n\ --couchbase-ram-quota=\"${COUCHBASE_RAM_QUOTA}\" \\\n\ @@ -84,16 +93,17 @@ CMD ["exec ./authorizer \\\n\ --smtp-local-name=\"${SMTP_LOCAL_NAME}\" \\\n\ --smtp-skip-tls-verification=\"${SMTP_SKIP_TLS_VERIFICATION:-false}\" \\\n\ --enable-strong-password=\"${ENABLE_STRONG_PASSWORD:-true}\" \\\n\ - --enable-totp-login=\"${ENABLE_TOTP_LOGIN:-false}\" \\\n\ --enable-basic-authentication=\"${ENABLE_BASIC_AUTHENTICATION:-true}\" \\\n\ --enable-email-verification=\"${ENABLE_EMAIL_VERIFICATION:-false}\" \\\n\ --enable-mobile-basic-authentication=\"${ENABLE_MOBILE_BASIC_AUTHENTICATION:-true}\" \\\n\ --enable-phone-verification=\"${ENABLE_PHONE_VERIFICATION:-false}\" \\\n\ --enable-magic-link-login=\"${ENABLE_MAGIC_LINK_LOGIN:-false}\" \\\n\ --enforce-mfa=\"${ENFORCE_MFA:-true}\" \\\n\ - --enable-mfa=\"${ENABLE_MFA:-false}\" \\\n\ - --enable-email-otp=\"${ENABLE_EMAIL_OTP:-false}\" \\\n\ - --enable-sms-otp=\"${ENABLE_SMS_OTP:-false}\" \\\n\ + --disable-totp-login=\"${DISABLE_TOTP_LOGIN:-false}\" \\\n\ + --disable-webauthn-mfa=\"${DISABLE_WEBAUTHN_MFA:-false}\" \\\n\ + --disable-email-otp=\"${DISABLE_EMAIL_OTP:-false}\" \\\n\ + --disable-sms-otp=\"${DISABLE_SMS_OTP:-false}\" \\\n\ + --disable-mfa=\"${DISABLE_MFA:-false}\" \\\n\ --enable-signup=\"${ENABLE_SIGNUP:-true}\" \\\n\ --twilio-account-sid=\"${TWILIO_ACCOUNT_SID}\" \\\n\ --twilio-api-key=\"${TWILIO_API_KEY}\" \\\n\ @@ -111,7 +121,9 @@ CMD ["exec ./authorizer \\\n\ --microsoft-client-id=\"${MICROSOFT_CLIENT_ID}\" \\\n\ --microsoft-client-secret=\"${MICROSOFT_CLIENT_SECRET}\" \\\n\ --microsoft-tenant-id=\"${MICROSOFT_TENANT_ID}\" \\\n\ + --microsoft-allowed-tenants=\"${MICROSOFT_ALLOWED_TENANTS}\" \\\n\ --microsoft-scopes=\"${MICROSOFT_SCOPES}\" \\\n\ + --oauth-allow-unverified-provider-email=\"${OAUTH_ALLOW_UNVERIFIED_PROVIDER_EMAIL:-false}\" \\\n\ --apple-client-id=\"${APPLE_CLIENT_ID}\" \\\n\ --apple-client-secret=\"${APPLE_CLIENT_SECRET}\" \\\n\ --apple-scopes=\"${APPLE_SCOPES}\" \\\n\ diff --git a/README.md b/README.md index 13af32d..a06c015 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Authorizer v2 requires the following variables. Configure them in Render's envir | `DATABASE_URL` | Database connection string | *(auto-configured by Render)* | | `JWT_TYPE` | JWT signing algorithm | `HS256` | | `JWT_SECRET` | JWT signing secret | `test` | +| `ENCRYPTION_KEY` | At-rest key for TOTP secrets and OTP digests. Required with `RS*`/`ES*` | *(output of `openssl rand -hex 32`)* | | `ADMIN_SECRET` | Admin secret for admin operations | `admin` | | `CLIENT_ID` | Client identifier **(required)** | `123456` | | `CLIENT_SECRET` | Client secret **(required)** | `secret` | @@ -37,7 +38,33 @@ Authorizer v2 requires the following variables. Configure them in Render's envir | `RATE_LIMIT_FAIL_CLOSED` | `true` = 503 on rate-limit backend errors (`--rate-limit-fail-closed`) | `false` | | `REDIS_URL` | Redis for sessions + shared rate limits if you scale to multiple instances | *(unset)* | -These are mapped to CLI flags at startup. Please refer to the [server configuration docs](https://docs.authorizer.dev/core/server-config) for all available flags. +These are mapped to CLI flags at startup. + +### Upgrading to 2.4.0 + +`ENABLE_EMAIL_VERIFICATION=true` with no SMTP configured is now a **fatal boot +error**, not a warning. Every account-recovery route ends at the same mailbox, +so without a mail path a user is created unverified and can never recover. If +you set it, also set `SMTP_HOST`, `SMTP_PORT` and `SMTP_SENDER_EMAIL` — all +three — or the container will exit on start. + +`APP_COOKIE_SAME_SITE` is now validated at boot too: an unrecognised value +exits rather than silently falling back to `lax`. + +Two optional flags were added for the 2.4.0 security changes, both defaulting +to the secure behaviour: + +- `OAUTH_ALLOW_UNVERIFIED_PROVIDER_EMAIL` — a social login whose provider did + not attest the email address no longer reaches an existing account. Set + `true` only as a temporary compatibility measure. +- `FGA_ALLOW_UNCONSTRAINED_AGENTS` — a delegated (agent-acting-for-user) check + against an authorization model with no `type agent` now denies. Set `true` + only while migrating a model. + +`MICROSOFT_ALLOWED_TENANTS` restricts which Entra tenants may sign in when +`MICROSOFT_TENANT_ID` is a multi-tenant alias (`common`/`organizations`/ +`consumers`). + Please refer to the [server configuration docs](https://docs.authorizer.dev/core/server-config) for all available flags. ## Notes diff --git a/render.yaml b/render.yaml index ddc2c91..be90741 100644 --- a/render.yaml +++ b/render.yaml @@ -24,12 +24,27 @@ services: generateValue: true - key: JWT_SECRET generateValue: true + # Encrypts TOTP secrets and OTP digests at rest. Required with RS*/ES*; + # with HS* it falls back to JWT_SECRET, but a distinct value keeps JWT + # secret rotation from locking out enrolled TOTP users. + - key: ENCRYPTION_KEY + generateValue: true - key: JWT_TYPE value: HS256 + - key: AUTHORIZER_URL + # Canonical/trusted base URL of this deployment (e.g. your Render + # service URL). When set, it is the only source used to build + # verification/reset/magic-link URLs, the JWT iss claim, and OIDC + # discovery URLs. Leaving it empty exposes host-header-injection + # account takeover (CWE-640) — set this in the Render dashboard + # once the service URL is known. + sync: false # ---------------------------------------------------------------- # April 2026 security hardening flags. See # https://docs.authorizer.dev/core/security for the full reference. # ---------------------------------------------------------------- + - key: OAUTH2_1_STRICT + value: "false" - key: TRUSTED_PROXIES # Render terminates TLS at their edge and routes traffic through # their own router. Set this in the Render dashboard to the