Describe the bug
The OIDC authorization code callback at /rustfs/admin/v3/oidc/callback is rejected by the s3s signature middleware with AccessDenied: Signature is required before reaching the OIDC handler.
The browser is redirected back from the IdP with valid code and state query parameters, but RustFS responds with HTTP 403 because the request (a browser-driven redirect from the IdP) cannot carry an AWS SigV4 signature.
This completely blocks OIDC login flows. Reproduced on both 1.0.0-beta.2 and 1.0.0-alpha.99.
To Reproduce
Steps to reproduce the behavior:
- Configure OIDC via environment variables:
RUSTFS_IDENTITY_OPENID_ENABLE=true
RUSTFS_IDENTITY_OPENID_CONFIG_URL=https://zitadel.example.com/.well-known/openid-configuration
RUSTFS_IDENTITY_OPENID_CLIENT_ID=<client-id>
RUSTFS_IDENTITY_OPENID_CLIENT_SECRET=<client-secret>
RUSTFS_IDENTITY_OPENID_SCOPES=openid,profile,email
RUSTFS_IDENTITY_OPENID_GROUPS_CLAIM=groups
RUSTFS_IDENTITY_OPENID_ROLES_CLAIM=roles
RUSTFS_IDENTITY_OPENID_DISPLAY_NAME=Zitadel
- Register the redirect URI in the IdP exactly as RustFS generates it:
https://<console-host>/rustfs/admin/v3/oidc/callback.
- Open the console at
https://<console-host>/ and click "Login with Zitadel."
- Authenticate at the IdP.
- The IdP redirects the browser back to
https://<console-host>/rustfs/admin/v3/oidc/callback?code=...&state=....
- RustFS responds with HTTP 403
AccessDenied: Signature is required. Login fails.
Expected behavior
The OIDC callback should be processed by the OIDC handler, the authorization code exchanged for tokens with the IdP, STS credentials issued, and the user logged into the console.
The callback handler should not require AWS SigV4 signatures — browser redirects from OIDC providers fundamentally cannot sign requests.
Logs
Authorize endpoint works correctly:
DEBUG http response generated in 316.931µs
status_code: 302 Found
uri: /rustfs/admin/v3/oidc/authorize/zitadel
location: https://zitadel.example.com/oauth/v2/authorize?response_type=code
&client_id=...&state=...&code_challenge=...&code_challenge_method=S256
&redirect_uri=https%3A%2F%2Fconsole.example.com%2Frustfs%2Fadmin%2Fv3%2Foidc%2Fcallback
&scope=openid+openid+profile+email&nonce=...
Callback fails:
DEBUG http started method: GET, url path: /rustfs/admin/v3/oidc/callback
DEBUG parsing path-style request, decoded_uri_path: "/rustfs/admin/v3/oidc/callback"
INFO s3s::ops::signature v2_check
INFO s3s::ops::signature v4_check
ERROR target: s3s::ops
message: "custom route returns error"
err: S3Error { code: AccessDenied, message: Some("Signature is required") }
DEBUG resp: Response { status: 403, headers: {"content-type": "application/xml"},
body: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Error><Code>AccessDenied</Code><Message>Signature is required</Message></Error>" }
The signature middleware (s3s::ops::signature::v2_check, v4_check) runs before the custom OIDC route handler. The OIDC callback route is registered behind the SigV4 middleware, which rejects unsigned requests — but OIDC callbacks from a browser cannot include SigV4 signatures.
Request headers on the failing callback confirm a normal browser redirect (correct Host, no Authorization, no x-amz-* signature headers):
host: console.example.com
referer: https://console.example.com/
user-agent: Mozilla/5.0 ... Safari/605.1.15
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
x-forwarded-proto: https
Workarounds attempted (none worked)
- Verified registered redirect URI in IdP matches RustFS-generated URI exactly.
- Toggled
RUSTFS_IDENTITY_OPENID_REDIRECT_URI_DYNAMIC true/false.
- Set / unset
RUSTFS_BROWSER_REDIRECT_URL.
- Tried separate hostnames for S3 (port 9000) and console (port 9001).
- Tried single hostname with path-based split (
/ → 9000, /rustfs/ → 9001).
- Downgraded from
1.0.0-beta.2 to 1.0.0-alpha.99 — identical error.
Additional observations
In the authorize 302 Location header, the scope parameter contains a duplicated openid:
scope=openid+openid+profile+email
with RUSTFS_IDENTITY_OPENID_SCOPES=openid,profile,email configured. This is likely benign. RustFS appears to prepend openid automatically even when it's already in the user-configured scopes list.
Possibly related: rustfs/console#107 and rustfs/console#108, which describe related architectural assumptions about console / S3 API origin sharing.
Environment
- RustFS version:
1.0.0-beta.2 (also reproduced on 1.0.0-alpha.99)
- Deployment: Debian 13
- IdP: Zitadel (self-hosted in k8s)
- Client: Safari on macOS / iPadOS
Checklist
Describe the bug
The OIDC authorization code callback at
/rustfs/admin/v3/oidc/callbackis rejected by the s3s signature middleware withAccessDenied: Signature is requiredbefore reaching the OIDC handler.The browser is redirected back from the IdP with valid
codeandstatequery parameters, but RustFS responds with HTTP 403 because the request (a browser-driven redirect from the IdP) cannot carry an AWS SigV4 signature.This completely blocks OIDC login flows. Reproduced on both
1.0.0-beta.2and1.0.0-alpha.99.To Reproduce
Steps to reproduce the behavior:
https://<console-host>/rustfs/admin/v3/oidc/callback.https://<console-host>/and click "Login with Zitadel."https://<console-host>/rustfs/admin/v3/oidc/callback?code=...&state=....AccessDenied: Signature is required. Login fails.Expected behavior
The OIDC callback should be processed by the OIDC handler, the authorization code exchanged for tokens with the IdP, STS credentials issued, and the user logged into the console.
The callback handler should not require AWS SigV4 signatures — browser redirects from OIDC providers fundamentally cannot sign requests.
Logs
Authorize endpoint works correctly:
Callback fails:
The signature middleware (
s3s::ops::signature::v2_check,v4_check) runs before the custom OIDC route handler. The OIDC callback route is registered behind the SigV4 middleware, which rejects unsigned requests — but OIDC callbacks from a browser cannot include SigV4 signatures.Request headers on the failing callback confirm a normal browser redirect (correct
Host, noAuthorization, nox-amz-*signature headers):Workarounds attempted (none worked)
RUSTFS_IDENTITY_OPENID_REDIRECT_URI_DYNAMICtrue/false.RUSTFS_BROWSER_REDIRECT_URL./→ 9000,/rustfs/→ 9001).1.0.0-beta.2to1.0.0-alpha.99— identical error.Additional observations
In the authorize 302
Locationheader, thescopeparameter contains a duplicatedopenid:with
RUSTFS_IDENTITY_OPENID_SCOPES=openid,profile,emailconfigured. This is likely benign. RustFS appears to prependopenidautomatically even when it's already in the user-configured scopes list.Possibly related: rustfs/console#107 and rustfs/console#108, which describe related architectural assumptions about console / S3 API origin sharing.
Environment
1.0.0-beta.2(also reproduced on1.0.0-alpha.99)Checklist