sftpgo
sftpgo copied to clipboard
[Bug]: OAuth 2.0 initialization request doesn't have code_challenge and code_challenge_method
⚠️ This issue respects the following points: ⚠️
- [x] This is a bug, not a question or a configuration issue.
- [x] This issue is not already reported on Github (I've searched it).
Bug description
According to OAuth2.0 docs, it's recommended to use PKCE for confidential clients for security best practice.
In this case client must send code_challenge and code_challenge_method to server when initialize request.
But I can't see code_challenge and code_challenge_method in initialization request and OIDC login fails.
https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.5.3.1
Steps to reproduce
- Configure OIDC authentication in SFTPGo.
- Try to login wtih OIDC.
- Inspect initialization request.
Expected behavior
It should send code_challenge and code_challenge_method as PKCE is recommended for confidential clients.
SFTPGo version
2.7.0
Data provider
PostgreSQL
Installation method
Community Docker image
Configuration
SFTPGO_HTTPD__BINDINGS__0__DISABLED_LOGIN_METHODS=2
SFTPGO_HTTPD__BINDINGS__0__OIDC__DEBUG=true
SFTPGO_HTTPD__BINDINGS__0__OIDC__CLIENT_ID=redacted
SFTPGO_HTTPD__BINDINGS__0__OIDC__CLIENT_SECRET=redacted
SFTPGO_HTTPD__BINDINGS__0__OIDC__CONFIG_URL=http://localhost:8002/audit/oauth2
SFTPGO_HTTPD__BINDINGS__0__OIDC__SCOPES="openid,profile,email,roles"
SFTPGO_HTTPD__BINDINGS__0__OIDC__REDIRECT_BASE_URL=http://localhost:18080
SFTPGO_HTTPD__BINDINGS__0__OIDC__USERNAME_FIELD=preferred_username
SFTPGO_HTTPD__BINDINGS__0__OIDC__IMPLICIT_ROLES=true
Relevant log output
2025-12-08 17:19:40,284 INFO middleware:_log:105 GET /audit/oauth2/authorize/?client_id=xxx&nonce=c68cc3424cf7384335081f134250239a6c529c55b12f0528149f6fe853d496b9&redirect_uri=http%3A%2F%2Flocalhost%3A18080%2Fweb%2Foidc%2Fredirect&response_type=code&scope=openid+profile+email+roles&state=e47560a9d1066f7f50e9bc260b67c212ebb314b2e0fe680925dfc1ac1d94e37b
2025-12-08 17:19:40,284 INFO middleware:_log:105 GET /audit/oauth2/authorize/?client_id=xxx&nonce=c68cc3424cf7384335081f134250239a6c529c55b12f0528149f6fe853d496b9&redirect_uri=http%3A%2F%2Flocalhost%3A18080%2Fweb%2Foidc%2Fredirect&response_type=code&scope=openid+profile+email+roles&state=e47560a9d1066f7f50e9bc260b67c212ebb314b2e0fe680925dfc1ac1d94e37b - 302
2025-12-08 17:19:40,284 INFO basehttp:log_message:213 "GET /audit/oauth2/authorize/?client_id=xxx&nonce=c68cc3424cf7384335081f134250239a6c529c55b12f0528149f6fe853d496b9&redirect_uri=http%3A%2F%2Flocalhost%3A18080%2Fweb%2Foidc%2Fredirect&response_type=code&scope=openid+profile+email+roles&state=e47560a9d1066f7f50e9bc260b67c212ebb314b2e0fe680925dfc1ac1d94e37b HTTP/1.1" 302 0
2025-12-08 17:19:40,509 INFO middleware:_log:105 POST /audit/oauth2/token/
2025-12-08 17:19:40,509 ERROR middleware:_log:105 {'Content-Length': '103', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'localhost:8002', 'User-Agent': 'Go-http-client/1.1', 'Authorization': '*****', 'Accept-Encoding': 'gzip'}
2025-12-08 17:19:40,509 ERROR middleware:_log:105 b'code=&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A18080%2Fweb%2Foidc%2Fredirect'
2025-12-08 17:19:40,509 INFO middleware:_log:105 POST /audit/oauth2/token/ - 400
2025-12-08 17:19:40,509 ERROR middleware:_log:105 {'Content-Type': 'application/json', 'Cache-Control': 'no-store', 'Pragma': 'no-cache'}
2025-12-08 17:19:40,509 ERROR middleware:_log:105 b'{"error": "invalid_grant"}'
2025-12-08 17:19:40,509 WARNING log:log_response:253 Bad Request: /audit/oauth2/token/
2025-12-08 17:19:40,510 WARNING basehttp:log_message:213 "POST /audit/oauth2/token/ HTTP/1.1" 400 26
2025-12-08 17:19:40,729 INFO middleware:_log:105 POST /audit/oauth2/token/
2025-12-08 17:19:40,729 ERROR middleware:_log:105 {'Content-Length': '297', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'localhost:8002', 'User-Agent': 'Go-http-client/1.1', 'Accept-Encoding': 'gzip'}
2025-12-08 17:19:40,729 ERROR middleware:_log:105 b'client_id=xxx&client_secret=xxx&code=&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A18080%2Fweb%2Foidc%2Fredirect'
2025-12-08 17:19:40,729 INFO middleware:_log:105 POST /audit/oauth2/token/ - 400
2025-12-08 17:19:40,729 ERROR middleware:_log:105 {'Content-Type': 'application/json', 'Cache-Control': 'no-store', 'Pragma': 'no-cache'}
2025-12-08 17:19:40,729 ERROR middleware:_log:105 b'{"error": "invalid_grant"}'
2025-12-08 17:19:40,729 WARNING log:log_response:253 Bad Request: /audit/oauth2/token/
2025-12-08 17:19:40,729 WARNING basehttp:log_message:213 "POST /audit/oauth2/token/ HTTP/1.1" 400 26
What are you using SFTPGo for?
Medium business
Additional info
I have implemented OIDC server using django-oauth-toolkit 3.1.0
{
"OAUTH2_VALIDATOR_CLASS": "xxx.utils.oauth2.validators.OAuth2Validator",
"SCOPES": {
"openid": "OpenID Connect scope",
"profile": "Profile",
"email": "Email",
"roles": "Roles",
},
"ALLOWED_REDIRECT_URI_SCHEMES": ["http", "https"] if STAGE in ["test", "local", "docker", "dev"] else ["https"],
"ALLOWED_SCHEMES": ["http", "https"] if STAGE in ["test", "local", "docker", "dev"] else ["https"],
"PKCE_REQUIRED": True,
"OIDC_ENABLED": True,
# Explicitly set because django-oauth-toolkit incorrectly guess correct scheme.
"OIDC_ISS_ENDPOINT": None if STAGE in ["test", "local", "docker"] else f"https://{DOMAIN}/{PRODUCT}/oauth2",
"OIDC_RSA_PRIVATE_KEY": env.str("OIDC_RSA_PRIVATE_KEY"),
"OIDC_RP_INITIATED_LOGOUT_ENABLED": True,
"OIDC_RP_INITIATED_LOGOUT_ALWAYS_PROMPT": True,
}