Skip to content

feat: OIDC Bearer token auth and documentation - #96

Open
SilviaSWR wants to merge 5 commits into
rexzhang:mainfrom
SilviaSWR:feature/integrate-access-token-authentication
Open

SilviaSWR wants to merge 5 commits into
rexzhang:mainfrom
SilviaSWR:feature/integrate-access-token-authentication

Conversation

@SilviaSWR

Copy link
Copy Markdown
Contributor

OIDC Bearer Token Authentication

Checklist

  • I have read the contribution guidelines
  • One Feature(issue) One PR
  • All commits in the PR will be merged into a single commit.
  • Add an entry in changelog.en.md if necessary? Don't forget to add your name and github profile link!
  • Add / update tests if necessary, Don't missing.
  • Add new / update outdated documentation

Description

Add HTTP Bearer token authentication using OpenID Connect (OIDC). When a client sends Authorization: Bearer <access_token>, the server verifies the JWT locally against the IdP's JWKS public keys (fetched at startup, no per-request network call), validates required claims (iss, aud, azp, typ, scope, exp), extracts preferred_username, and resolves permissions from account_mapping.

What's new

  • HTTPOIDCAuth class (asgi_webdav/auth.py) — verifies JWTs locally against JWKS public keys. Eagerly fetches keys at startup; failure is fatal.
  • DAVPasswordType.OIDC — new password type with format <oidc>#1#issuer#jwks_uri#audience#client_id#algorithm#scope.
  • *oidc sentinel user — mirrors the *ldap convention. Configures the OIDC provider and serves as the default permission template for authenticated Bearer users not explicitly listed in account_mapping.
  • Bearer auth in DAVAuth.pick_out_user() — handles Authorization: Bearer header, verifies token, looks up user permissions, falls back to *oidc template.
  • WWW-Authenticate: Bearer appended to 401 challenge when OIDC is configured.

Configuration

Add a *oidc entry to account_mapping:

{
  "account_mapping": [
    {
      "username": "*oidc",
      "password": "<oidc>#1#https://idp.example.com/realms/PIC#https://idp.example.com/realms/PIC/protocol/openid-connect/certs#account#cosmohub-test#RS256#openid",
      "permissions": ["+^/$"]
    }
  ]
}

Install the optional dependency: pip install ASGIWebDAV[oidc]

Key design decisions

  • Local verification — JWTs are verified against JWKS public keys without calling the IdP per request. Revoked tokens remain valid until expiry (typically 5-15 min). This avoids IdP latency and load.
  • Fallback behavior — Unknown Bearer users inherit *oidc template permissions. Invalid Bearer tokens always return 401 (never degrade to anonymous).
  • Basic auth rejection — Basic auth against an OIDC-configured user explicitly fails; the *oidc password field is only used for JWT configuration.
  • Optional dependency — PyJWT + cryptography are in a separate [oidc] extra to avoid bloating the core install.

Files changed

File Change
asgi_webdav/auth.py HTTPOIDCAuth class, DAVPasswordType.OIDC, Bearer handling in pick_out_user() and create_response_401()
requirements.d/oidc.txt New — PyJWT>=2.11.0, cryptography
requirements.d/full.txt Added -r oidc.txt
pyproject.toml Added [oidc] extra
tests/conftest.py Skip tests if PyJWT not installed
tests/test_auth_oidc.py 247-line test suite — token parsing, claim verification, user lookup, fallback, edge cases
docs/guide/authentication.en.md Updated auth flow diagram, added Bearer auth section
docs/guide/protect-your-password-in-the-config.en.md Full OIDC configuration reference, compatibility table
docs/changelog.en.md v2.1.0 entry

fixes #95

@codecov

codecov Bot commented Jul 16, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.59091% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.52%. Comparing base (04e3760) to head (51b4234).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
asgi_webdav/auth.py 96.59% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #96      +/-   ##
==========================================
+ Coverage   76.00%   76.52%   +0.51%     
==========================================
  Files          26       26              
  Lines        3776     3863      +87     
==========================================
+ Hits         2870     2956      +86     
- Misses        906      907       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

SilviaSWR added 2 commits July 16, 2026 16:33
Add tests for HTTPOIDCAuth.__init__ failure modes (jwt not installed,
unsupported password version, JWKS fetch error), verify_token jwt=None
guard, DAVAuth init with wrong *oidc password format, and bearer
pick_out_user when user is unknown with no fallback template.
{
"username": "*oidc",
"password": "<oidc>#1#https://idp.example.com/realms/PIC#https://idp.example.com/realms/institution/protocol/openid-connect/certs#account#cosmohub-test#RS256#openid",
"permissions": ["+^/$"]

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a example that without permissions in config file

@rexzhang rexzhang Jul 19, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all info(username and permissions) come from oauth maybe better in real deploy

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey,

Implemented OIDC groups-based permission resolution. Permissions can now
come from the access_token's groups claim.

What changed:

  • password format: 8 → 9 fields, 9th is group_prefix (e.g.
    asgi-webdav_).
  • HTTPOIDCAuth stores the prefix.
  • New _extract_groups_permissions() filters token groups by prefix,
    strips prefix, returns permission list.
  • pick_out_user now has 3-tier priority:
    1. User in config → config permissions (groups ignored)
    2. User not in config, has matching groups → groups as permissions
    3. User not in config, no matching groups → *oidc template fallback
  • 6 new tests covering all priority paths, prefix filtering, empty
    groups, no groups claim.
  • Updated docs.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a new example that without permissions in config file. If possible, please add the configuration information for the OIDC porvider(Keycloak) part.

@rexzhang

Copy link
Copy Markdown
Owner

Support OIDC is greate idea! Is it compatible with Authelia?

btw: I'll be 2-4 weeks before I have time to do a full review.

The  password format expands from 8 to 9 fields, adding a
 (e.g. ). When an OIDC Bearer user is not
listed in , the server now extracts permissions from the
token's pic mhedas test_proxy users claim, filtering by prefix and stripping it before use.

Priority chain:
1. User in config → config permissions (groups ignored)
2. User not in config, has matching groups → groups as permissions
3. User not in config, no matching groups → *oidc template fallback
4. No *oidc template → denied

Breaking: existing 8-field <oidc> configs must add a 9th field.
@SilviaSWR
SilviaSWR force-pushed the feature/integrate-access-token-authentication branch from bfb1e8b to 597ee54 Compare July 20, 2026 11:55
@SilviaSWR

Copy link
Copy Markdown
Contributor Author

This implementation is designed specifically for Keycloak. It relies on Keycloak-specific behavior, such as the typ: Bearer value in access tokens and the preferred_username claim. Authelia is not supported and would likely fail the typ validation.

@rexzhang

Copy link
Copy Markdown
Owner

This implementation is designed specifically for Keycloak. It relies on Keycloak-specific behavior, such as the typ: Bearer value in access tokens and the preferred_username claim. Authelia is not supported and would likely fail the typ validation.

This is a real sad. I didn't use Keycloak, so please provide as much detailed documentation as possible on how to integrate it with Keycloak.

@SilviaSWR

Copy link
Copy Markdown
Contributor Author

Sorry, I didn't explain myself clearly.

The feature was developed and tested using Keycloak backed by FreeIPA, but the implementation itself only relies on the standard OpenID Connect authentication flow and OAuth 2.0 specifications. It does not depend on any Keycloak-specific APIs or features, so in principle it should work with any standards-compliant OIDC provider.

The only part that is provider-specific is the configuration of the issued access token. The application expects the access token to contain a set of standard claims (issuer, audience, scopes, username, etc.). These are mostly defined by the OpenID Connect and OAuth 2.0 specifications rather than by Keycloak itself.

Based on your comment, I realized this wasn't documented clearly enough, so I've added documentation describing the required access token claims and what each of them is used for. This should make it easier to configure other providers, such as Authelia, Authentik, Dex, or Zitadel, to be compatible with the application.

Since our environment uses Keycloak, I haven't been able to verify the configuration with Authelia myself. If you happen to configure OpenID Connect with Authelia following the documentation, I'd be interested to know whether everything works as expected. That would help confirm that the documentation is complete.

@SilviaSWR

Copy link
Copy Markdown
Contributor Author

Hi @rexzhang, just following up on this PR. Have you had a chance to review it? I’d be happy to address any feedback or make any changes needed. Thanks!

@SilviaSWR
SilviaSWR requested a review from rexzhang September 17, 2026 16:16
@rexzhang

Copy link
Copy Markdown
Owner

Hi @SilviaSWR , I will review it during the October 1st holiday.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: OIDC Bearer Token Authentication

2 participants