oauth2-proxy/oauth2-proxy · error

failed to retrieve user info: %v

Error message

failed to retrieve user info: %v

What it means

EnrichSession is called after the OAuth token is redeemed to add GitLab user info and allowed-projects data to the session. This error wraps any failure from p.getUserinfo, i.e. the HTTP GET to the GitLab /user endpoint (via the userinfo URL) failed or its response could not be unmarshalled. The session is rejected, so the user cannot authenticate.

Source

Thrown at providers/gitlab.go:128

}

// setProjectScope ensures read_api is added to scope when filtering on projects
func (p *GitLabProvider) setProjectScope() {
	for _, val := range strings.Split(p.Scope, " ") {
		if val == "read_api" {
			return
		}
	}
	p.Scope += " read_api"
}

// EnrichSession enriches the session with the response from the userinfo API
// endpoint & projects API endpoint for allowed projects.
func (p *GitLabProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {
	// Retrieve user info
	userinfo, err := p.getUserinfo(ctx, s)
	if err != nil {
		return fmt.Errorf("failed to retrieve user info: %v", err)
	}

	// Check if email is verified
	if !p.AllowUnverifiedEmail && !userinfo.EmailVerified {
		return fmt.Errorf("user email is not verified")
	}

	if userinfo.Nickname != "" {
		s.User = userinfo.Nickname
	}
	if userinfo.Email != "" {
		s.Email = userinfo.Email
	}
	if len(userinfo.Groups) > 0 {
		s.Groups = userinfo.Groups
	}

	// Add projects as `project:blah` to s.Groups

View on GitHub (pinned to 33c2eb92de)

Solutions

  1. Read the wrapped inner error (%v) in the log — it tells you whether it was an HTTP status failure or an unmarshal problem.
  2. Verify the access token is valid: re-run the auth flow; if it recurs per-request, check token lifetime/refresh configuration.
  3. Test connectivity from the oauth2-proxy host: curl -H 'Authorization: Bearer <token>' https://<gitlab>/api/v4/user.
  4. If self-hosted, confirm the gitlab endpoint/oidc URLs in config point to the correct reachable instance and that TLS is trusted.
  5. Check the GitLab instance status (API rate limits, maintenance) if the failure is intermittent.

Example fix

// before (reverse proxy returning HTML on /api/v4/user)
# gitlab endpoint pointing at web UI proxy
gitlab = "https://gitlab.example.com"
// after
gitlab = "https://gitlab-api.example.com" # direct, API-capable endpoint
Defensive patterns

Strategy: try-catch

Validate before calling

resp, err := http.Get(gitlabURL + "/api/v4/user") // basic reachability check before configuring
if err != nil { return fmt.Errorf("gitlab unreachable: %w", err) }

Try / catch

if err := provider.EnrichSession(ctx, session); err != nil {
    if strings.Contains(err.Error(), "failed to retrieve user info") {
        // inspect wrapped cause, optionally retry once on transient network errors
        log.Printf("gitlab userinfo unavailable: %v", err)
        http.Error(rw, "upstream unavailable", http.StatusBadGateway)
        return
    }
    return err
}

Prevention

When it happens

Trigger: The GET to the GitLab userinfo URL fails: network/DNS failure, GitLab returning a non-2xx (401 on an expired/invalid access token, 403, 5xx), or a response body that does not unmarshal into the userinfo struct.

Common situations: Access token revoked or expired between redeem and enrich; self-hosted GitLab behind a misconfigured reverse proxy returning HTML error pages; network egress blocked from the proxy container; GitLab instance temporarily down.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of oauth2-proxy/oauth2-proxy@33c2eb92de (2026-09-06). Data as JSON: /api/errors/db4544e07f693689. Report an issue: GitHub.