Bug report
- [ x] I confirm this is a bug with Supabase, not with my own application.
- [ x] I confirm I have searched the Docs, GitHub Discussions, and Discord.
Describe the bug
When self-hosting Supabase with a reverse proxy (nginx), the ip_address field in auth.audit_log_entries is always empty, even when:
GOTRUE_SECURITY_SB_FORWARDED_FOR_ENABLED=true is set
- The reverse proxy sends the
Sb-Forwarded-For header with the client IP
- GoTrue v2.186.0+ is used (which added Sb-Forwarded-For support)
The user_agent field is also not persisted to the database, though it does appear in GoTrue's stdout logs.
Steps to Reproduce
- Deploy self-hosted Supabase with Docker
- Configure nginx reverse proxy with:
proxy_set_header Sb-Forwarded-For $remote_addr;
- Set
GOTRUE_SECURITY_SB_FORWARDED_FOR_ENABLED=true in GoTrue environment
- Perform a signup/login through the reverse proxy
- Query the audit log:
SELECT ip_address, payload->>'action', payload->>'actor_username'
FROM auth.audit_log_entries
ORDER BY created_at DESC LIMIT 5;
Expected Behavior
ip_address should contain the client IP from the Sb-Forwarded-For header
user_agent should be persisted in the payload
Actual Behavior
ip_address is always empty string ''
user_agent appears in GoTrue stdout logs but is not in the database payload:
GoTrue stdout (has user_agent):
{"auth_audit_event":{"action":"login","ip_address":"","user_agent":"Mozilla/5.0..."},...}
Database payload (missing user_agent):
{"action":"login","actor_id":"...","traits":{"provider":"email"}}
Root Cause Analysis
After tracing through the code:
-
sbff.Middleware correctly extracts IP from Sb-Forwarded-For header and stores it in request context
-
sbff.GetIPAddress(req) can retrieve the IP for rate limiting (this works)
-
However, callers of NewAuditLogEntry() pass "" for the IP address parameter:
// From internal/api/token.go, signup.go, etc.
models.NewAuditLogEntry(config.AuditLog, r, tx, user, models.LoginAction, "", map[string]interface{}{...})
// ^^
// Empty string passed for IP
-
NewAuditLogEntry() does not extract IP from the request context - it only uses the value passed to it
Proposed Fix
Callers of NewAuditLogEntry() should use sbff.GetIPAddress(req) to extract the IP:
ipAddress := ""
if addr, ok := sbff.GetIPAddress(r); ok {
ipAddress = addr
}
models.NewAuditLogEntry(config.AuditLog, r, tx, user, models.LoginAction, ipAddress, traits)
Or alternatively, NewAuditLogEntry() could extract the IP from the request context when an empty string is passed.
Environment
- GoTrue version: v2.186.0 (also tested v2.184.0)
- Deployment: Self-hosted Docker
- Reverse proxy: nginx
- OS: Linux/macOS
Related
Bug report
Describe the bug
When self-hosting Supabase with a reverse proxy (nginx), the
ip_addressfield inauth.audit_log_entriesis always empty, even when:GOTRUE_SECURITY_SB_FORWARDED_FOR_ENABLED=trueis setSb-Forwarded-Forheader with the client IPThe
user_agentfield is also not persisted to the database, though it does appear in GoTrue's stdout logs.Steps to Reproduce
GOTRUE_SECURITY_SB_FORWARDED_FOR_ENABLED=truein GoTrue environmentExpected Behavior
ip_addressshould contain the client IP from theSb-Forwarded-Forheaderuser_agentshould be persisted in the payloadActual Behavior
ip_addressis always empty string''user_agentappears in GoTrue stdout logs but is not in the database payload:GoTrue stdout (has user_agent):
{"auth_audit_event":{"action":"login","ip_address":"","user_agent":"Mozilla/5.0..."},...}Database payload (missing user_agent):
{"action":"login","actor_id":"...","traits":{"provider":"email"}}Root Cause Analysis
After tracing through the code:
sbff.Middlewarecorrectly extracts IP fromSb-Forwarded-Forheader and stores it in request contextsbff.GetIPAddress(req)can retrieve the IP for rate limiting (this works)However, callers of
NewAuditLogEntry()pass""for the IP address parameter:NewAuditLogEntry()does not extract IP from the request context - it only uses the value passed to itProposed Fix
Callers of
NewAuditLogEntry()should usesbff.GetIPAddress(req)to extract the IP:Or alternatively,
NewAuditLogEntry()could extract the IP from the request context when an empty string is passed.Environment
Related
GOTRUE_SECURITY_SB_FORWARDED_FOR_ENABLEDfeature was added in v2.186.0 (feat: Add Sb-Forwarded-For header and IP-based rate limiting #2295) for rate limiting, but audit logging was not updated to use it.