Skip to content

User interface doesn't expose sub claim (required by OIDC specification) #6

@Sam-Lam-Varadise

Description

@Sam-Lam-Varadise

Issue: Missing sub Claim in User Interface

Summary

The User interface does not expose the sub (subject) claim, which is mandatory according to the OpenID Connect specification. This creates an OIDC compliance issue and limits interoperability with standard OIDC providers.

OIDC Specification Requirements

According to the OpenID Connect Core 1.0 specification:

  • ID Token (Section 2): sub is a REQUIRED claim
  • UserInfo Response (Section 5.1): sub is a REQUIRED claim

The sub claim is the unique identifier for the end-user at the issuer and serves as the primary key for user identity.

Current Implementation

File: packages/react-native-oidc-auth-core/src/oidc-auth/interface/user.ts

export interface User {
  id?: string;
  username?: string;
  email?: string;
  firstName?: string;
  lastName?: string;
  enabled?: boolean;
  emailVerified?: boolean;
  totp?: boolean;
  createdTimestamp?: number;
}

Issues:

  1. ❌ No sub field (OIDC required claim)
  2. ✅ Has id field (appears to be Keycloak-specific)
  3. ✅ Has Keycloak-specific fields (enabled, totp, createdTimestamp)

Root Cause Analysis

The library appears to have been originally designed for Keycloak, which:

  • Provides a non-standard /account endpoint (used in oidc-auth-bare.ts line 78)
  • Uses id as the user identifier in its admin/account APIs rather than the standard OIDC sub
  • Includes additional user properties not in standard OIDC UserInfo

Evidence:

  1. JwtToken interface does include sub (used for tokens) - see packages/react-native-oidc-auth-core/src/oidc-auth/interface/jwt-token.ts
  2. But User interface doesn't expose it when calling /userinfo endpoint
  3. The getUserInfo implementations don't map the sub claim from the response

Impact

Compatibility Issues:

  • ❌ Not compliant with OIDC specification
  • ❌ Cannot reliably identify users across OIDC providers (some use id, some don't)
  • sub is the only guaranteed unique identifier in OIDC
  • email can change, username may not exist, but sub is immutable

Real-world scenarios where this matters:

  • Multi-tenant applications
  • User migration between identity providers
  • Auditing and compliance (need stable user identifier)
  • Integration with standard OIDC providers (Auth0, Okta, Azure AD, etc.)

Proposed Solution

Option 1: Add sub to User interface (Recommended)

export interface User {
  sub: string;                    // ✅ OIDC required - unique subject identifier
  id?: string;                    // Keep for Keycloak compatibility
  username?: string;
  email?: string;
  firstName?: string;
  lastName?: string;
  enabled?: boolean;
  emailVerified?: boolean;
  totp?: boolean;
  createdTimestamp?: number;
}

Update getUserInfo implementations to include sub:

In oidc-auth-expo.ts:

return {
  sub: result.sub,              // ✅ Add this
  email: result.email,
  // ... rest of fields
};

In oidc-auth-bare.ts:

return {
  sub: result.sub,              // ✅ Add this
  email: result.email,
  // ... rest of fields
};

Option 2: Use standard OIDC UserInfo claims

Alternatively, align the entire User interface with the standard OIDC UserInfo claims:

export interface User {
  // Standard OIDC claims
  sub: string;                    // Required
  name?: string;
  given_name?: string;
  family_name?: string;
  middle_name?: string;
  nickname?: string;
  preferred_username?: string;
  profile?: string;
  picture?: string;
  website?: string;
  email?: string;
  email_verified?: boolean;
  gender?: string;
  birthdate?: string;
  zoneinfo?: string;
  locale?: string;
  phone_number?: string;
  phone_number_verified?: boolean;
  address?: Address;
  updated_at?: number;
  
  // Keycloak-specific (keep as optional for backward compatibility)
  id?: string;
  enabled?: boolean;
  totp?: boolean;
  createdTimestamp?: number;
}

Affected Files

  • packages/react-native-oidc-auth-core/src/oidc-auth/interface/user.ts (interface definition)
  • packages/react-native-oidc-auth-expo/src/oidc-auth-expo.ts (getUserInfo implementation)
  • packages/react-native-oidc-auth/src/oidc-auth-bare.ts (getUserInfo implementation)

Testing Considerations

  • Verify sub is correctly mapped from UserInfo endpoint response
  • Test with multiple OIDC providers (not just Keycloak)
  • Ensure backward compatibility with existing Keycloak integrations
  • Update TypeScript types and examples

References


Would you be open to a PR implementing Option 1? This would maintain backward compatibility while adding OIDC compliance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions