Skip to content

feat: allow using external_id as the subject in OAuth2 login flows #4528

@Micaso

Description

@Micaso

Preflight checklist

Ory Network Project

No response

Describe your problem

With the recent introduction of the external_id field in Kratos identities, there is a strong use case for using this ID as the sub (subject) claim when Kratos acts as an identity provider for Ory Hydra.

Currently, Kratos always passes the internal UUID. For organizations migrating legacy systems or integrating with third-party services that rely on specific string-based identifiers, being able to map external_id to the OIDC sub claim is essential.

Describe your ideal solution

Proposed Changes

  • Configuration: Added oauth2_provider.use_external_id (boolean, default: false).
  • Hydra Integration: Updated the AcceptLoginRequest logic to check this configuration. If enabled and the identity has an external_id, it is used as the subject for Hydra.
  • Hooks: Updated PostLoginHook to pass the ExternalID from the identity to the Hydra service wrapper.

Technical Breakdown

  • Modified driver/config to support the new toggle.
  • Updated embedx/config.schema.json for validation.
  • Updated hydra/hydra.go to handle the conditional subject logic.
  • Updated selfservice/flow/login/hook.go to extract ExternalID from the identity during the login flow.

Workarounds or alternatives

An alternative is to bypass the native Kratos-Hydra integration by not configuring oauth2_provider.url in Kratos. In this scenario, a custom middleware or backend would manage the login completion, fetch the Kratos Identity, and manually call Hydra's acceptLoginRequest with the external_id as the subject.

While the workaround works, it requires developers to write and maintain "glue code" for a common use case. Supporting this natively in Kratos simplifies the architecture for anyone using the external_id feature and ensures a more robust, standard-compliant integration.

Version

v25.4.0

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    featNew feature or request.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions