Skip to content

oidc: Traceback upon first login with self-hosted Kanidm OIDC #1641

@jprenken

Description

@jprenken

Describe the bug

When using an OIDC IdP that doesn't populate an email field in the token, the /oidc/token endpoint will fail to populate the external connection schema's name field with a valid string, causing a traceback and 500.

To Reproduce

Steps to reproduce the behavior:

  1. With a self-hosted Kanidm instance, configure a public client for Appointment:
kanidm group create tba_users
kanidm group add-members tba_users example_username
kanidm system oauth2 create-public tba Appointment https://appt.example.com
kanidm system oauth2 add-redirect-url tba https://appt.example.com/post-login/
kanidm system oauth2 update-scope-map tba tba_users email openid profile
  1. Configure backend/.env for OIDC:
AUTH_SCHEME=oidc
OIDC_CLIENT_ID=tba
OIDC_TOKEN_INTROSPECTION_URL=https://kanidm.example.com/oauth2/token/introspect

(No OIDC_CLIENT_SECRET; this is a public client.)

  1. Configure frontend/.env for OIDC:
VITE_AUTH_SCHEME=oidc
VITE_OIDC_CLIENT_ID=tba
VITE_OIDC_ROOT_URL=https://kanidm.example.com/oauth2/openid/tba
  1. Visit your TBA instance and, when redirected to Kanidm, log in.

Expected behavior

You should be redirected into TBA's flow to configure your new subscriber account.

Actual behavior

You receive a blank browser page, and the backend outputs a traceback ending with:

  File "/app/appointment/routes/auth.py", line 625, in oidc_token
    external_connection_schema = schemas.ExternalConnection(
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/pydantic/main.py", line 263, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for ExternalConnection
name
  Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]
    For further information visit https://errors.pydantic.dev/2.13/v/string_type

Additional context

routes/auth.py attempts to populate external_connection_schema.name with the value of token_data.get('email'). It doesn't handle cases where that value is missing or empty. Replacing that line with name=email, (since email has been set with more robust logic) works around this problem, but I don't know if it actually follows the intended logic here.

I'm still trying to troubleshoot why token_data doesn't end up containing an email field.

(Thanks for making this open source and self-hostable!)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions