Skip to content

HEADER_MAPPING fails when userinfo claim is missing from JWT #143

@sanderaasmaa

Description

@sanderaasmaa

Problem

HEADER_MAPPING only reads from claims["userinfo"] in the JWT (proxy.go:96). When the OIDC userinfo doesn't survive fosite's authorization code exchange (the Extra field on the JWT session isn't preserved through handleToken), the userinfo claim is absent from the access token JWT, and no headers are mapped.

The user's email IS available as the top-level sub claim (set via OIDC_USER_ID_FIELD=/email), but HEADER_MAPPING doesn't read from top-level claims.

Steps to reproduce

  1. Configure with Azure AD OIDC + HEADER_MAPPING=/email:X-User-Email
  2. Authenticate via the OAuth flow (Claude Teams MCP client)
  3. Make a tool call — the X-User-Email header is not set on the proxied request
  4. Debug logging on the upstream server confirms no x-user-email in received headers

Expected behavior

HEADER_MAPPING=/email:X-User-Email should set X-User-Email to the user's email, reading from claims["userinfo"]["email"] OR falling back to claims["sub"] when userinfo is absent.

Suggested fix

In pkg/proxy/proxy.go, after the existing userinfo mapping block, add a fallback that reads from top-level JWT claims:

if len(p.headerMapping) > 0 {
    if claims, ok := token.Claims.(jwt.MapClaims); ok {
        // Try userinfo claim first (existing behavior)
        source := claims
        if userinfo, exists := claims["userinfo"]; exists {
            if ui, ok := userinfo.(map[string]any); ok {
                source = ui
            }
        }
        for pointer, headerName := range p.headerMapping {
            // ... existing mapping logic using source instead of userinfo
        }
    }
}

Or simpler: when a pointer like /email isn't found in userinfo, fall back to the top-level claim sub (or whatever matches).

Environment

  • mcp-auth-proxy v2.8.1
  • Azure AD OIDC (Microsoft Entra ID)
  • Transparent proxy mode (HTTP target)
  • OIDC_USER_ID_FIELD=/email

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions