Skip to content

fix: support async authenticate() and propagate auth to SubRouters#1331

Open
sansyrox wants to merge 3 commits intomainfrom
fix/async-auth-handler-support
Open

fix: support async authenticate() and propagate auth to SubRouters#1331
sansyrox wants to merge 3 commits intomainfrom
fix/async-auth-handler-support

Conversation

@sansyrox
Copy link
Copy Markdown
Member

@sansyrox sansyrox commented Mar 15, 2026

Summary

Closes #1296

  • Async authenticate() support: The auth middleware wrapper in add_auth_middleware is now async def and uses inspect.isawaitable() to detect and await async authenticate() implementations. This enables users to use async ORMs, HTTP clients, and other async I/O directly in their AuthenticationHandler.authenticate() method.
  • Auth propagation to SubRouters: Both configure_authentication() and include_router() now propagate the parent app's authentication handler to SubRouters that haven't configured their own. This works regardless of call order — whether include_router or configure_authentication is called first.
  • Docs: Updated AuthenticationHandler.authenticate() docstring to document async override support.

Changes

File Change
robyn/router.py inner_handler in add_auth_middleware is now async def; awaits result if authenticate() is async
robyn/__init__.py include_router and configure_authentication propagate auth handler to SubRouters
robyn/authentication.py Docstring updated to document async support
integration_tests/subroutes/auth_subrouter.py New: SubRouter with async auth handler + SubRouter testing inherited auth
integration_tests/test_async_authentication.py New: 6 tests for async auth and inherited auth

Test plan

  • Existing sync auth tests still pass (regression)
  • Async auth handler: valid token returns 200 with correct identity
  • Async auth handler: invalid/missing token returns 401
  • Inherited auth on SubRouter: valid token returns 200
  • Inherited auth on SubRouter: invalid/missing token returns 401
  • SubRouter with its own auth handler is NOT overwritten by parent's

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Support for asynchronous authentication handlers
    • Authentication inheritance for included sub-routers (child routers inherit parent auth when not configured)
  • Tests

    • Integration tests covering async authentication and inheritance scenarios
  • Documentation

    • Clarified auth handler docs: async/sync implementations and None-to-reject behavior
  • Chores

    • CI updated and added automated Discord release notifications upon successful releases

…1296)

The authentication middleware wrapper is now async-aware: if
`AuthenticationHandler.authenticate()` is overridden as an `async def`,
the framework awaits it automatically, enabling async ORMs, HTTP clients,
and other async I/O in authentication logic.

Additionally, `configure_authentication()` and `include_router()` now
propagate the parent app's authentication handler to SubRouters that
have not configured their own, so `auth_required=True` routes on
SubRouters work without a separate `configure_authentication()` call.

Closes #1296

Made-with: Cursor
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
robyn Ready Ready Preview, Comment Mar 28, 2026 8:09pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d8500900-7ad7-4100-96b6-360b6ed78ca2

📥 Commits

Reviewing files that changed from the base of the PR and between 1857c3c and 2988e6a.

📒 Files selected for processing (1)
  • .github/workflows/release-CI.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/release-CI.yml

📝 Walkthrough

Walkthrough

Adds async-capable authentication (authenticate may be awaited), propagates parent authentication_handler to included SubRouters when they lack one, adds integration tests for async and inherited auth subrouters, and adds a Discord release-notify job to the release CI workflow.

Changes

Cohort / File(s) Summary
CI / Release Workflow
​.github/workflows/release-CI.yml
Updated checkout to actions/checkout@v4; added discord-notify job that computes changelog from git and posts a JSON payload to a Discord webhook on successful tag releases.
Core Authentication
robyn/authentication.py, robyn/router.py, robyn/__init__.py
Made authentication wrapper always async and await authenticate results when awaitable; docstring clarifications for async/sync authenticate and None to reject; propagate parent's authentication_handler to SubRouters at include/configure time and apply to their middleware.
New Auth Subrouters (tests)
integration_tests/subroutes/auth_subrouter.py, integration_tests/subroutes/__init__.py, integration_tests/base_routes.py
Added AsyncAuthHandler, async_auth_subrouter, and inherited_auth_subrouter; exported routers and registered them in base routes.
Integration Tests
integration_tests/test_async_authentication.py
Added tests covering async authentication and inherited auth behavior (valid/invalid tokens, 401 responses, WWW-Authenticate header expectations).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Router as "MiddlewareRouter / SubRouter"
    participant Auth as "AuthenticationHandler"
    participant Endpoint as "Protected Endpoint"

    Client->>Router: HTTP Request (with/without Bearer token)
    Router->>Auth: call authenticate(token)
    Note right of Auth: authenticate may return value or coroutine
    Auth-->>Router: Identity or None (awaited if coroutine)
    alt Identity returned
        Router->>Endpoint: call handler with identity
        Endpoint-->>Client: 200 OK + body
    else None returned
        Router-->>Client: 401 Unauthorized + WWW-Authenticate
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through routers, async and spry,
Awaiting tokens beneath the sky,
Parent rules ripple to each sub den,
Tests hop in, then celebrate again—
Discord pings, and I nibble a carrot. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: support async authenticate() and propagate auth to SubRouters' directly and specifically describes the two main changes in the PR.
Description check ✅ Passed The PR description is comprehensive, including a clear summary, detailed change breakdown, and explicit test plan aligned with the template.
Linked Issues check ✅ Passed All coding requirements from issue #1296 are met: async authenticate() support with proper awaiting [robyn/router.py], auth handler propagation to SubRouters [robyn/init.py], and comprehensive tests validating async and inherited auth scenarios.
Out of Scope Changes check ✅ Passed All changes are directly related to the PR objectives: async auth support, auth propagation, documentation updates, and comprehensive integration tests. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/async-auth-handler-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/release-CI.yml (1)

223-239: Guard against Discord message-length failures.

The composed payload can exceed Discord webhook content limits on large releases, causing curl -f to fail the job. Consider truncating changelog before payload creation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-CI.yml around lines 223 - 239, The Discord payload
can exceed webhook content limits when CHANGELOG is large, causing the curl call
using PAYLOAD to fail; before constructing MESSAGE/PAYLOAD, truncate CHANGELOG
to a safe length (e.g., 1900–2000 chars) and append an ellipsis or “(truncated)”
marker, ensure the truncated string is valid UTF-8, then use that truncated
variable when forming MESSAGE and PAYLOAD that are sent to DISCORD_WEBHOOK_URL
via curl; modify the block that builds MESSAGE, PAYLOAD, and calls curl to
perform this truncation and marking.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release-CI.yml:
- Around line 220-221: PREV_TAG may be empty on first release and the grep in
CHANGELOG can return non-zero (exit 1) when there are no matching lines, which
breaks the job; update the release script so PREV_TAG is set to a sensible
fallback (e.g., the repository root commit via git rev-list --max-parents=0 HEAD
or treat it as empty range) when the tag lookup (PREV_TAG=$(git tag ... | sed -n
'2p')) yields nothing, and make the CHANGELOG assignment resilient by preventing
grep from failing the script (e.g., append an unconditional success fallback
like "|| true" or use a conditional/alternate git log invocation) so CHANGELOG
becomes an empty string instead of causing an exit; adjust the lines that set
PREV_TAG and CHANGELOG accordingly to avoid failing under set -e.
- Line 212: The workflow step currently references actions/checkout@v3 which
uses Node.js 16; update the checkout action to a supported major (e.g.,
actions/checkout@v4 or later) by replacing the uses: entry for the checkout step
in the release-CI workflow; after updating the version (actions/checkout@v4 or
`@v5/`@v6) run the workflow or a local lint/CI dry run to ensure there are no
breaking input/API changes.

---

Nitpick comments:
In @.github/workflows/release-CI.yml:
- Around line 223-239: The Discord payload can exceed webhook content limits
when CHANGELOG is large, causing the curl call using PAYLOAD to fail; before
constructing MESSAGE/PAYLOAD, truncate CHANGELOG to a safe length (e.g.,
1900–2000 chars) and append an ellipsis or “(truncated)” marker, ensure the
truncated string is valid UTF-8, then use that truncated variable when forming
MESSAGE and PAYLOAD that are sent to DISCORD_WEBHOOK_URL via curl; modify the
block that builds MESSAGE, PAYLOAD, and calls curl to perform this truncation
and marking.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e05fa1b-b198-45a8-a050-7e81a351414d

📥 Commits

Reviewing files that changed from the base of the PR and between 4a2104d and 1857c3c.

📒 Files selected for processing (8)
  • .github/workflows/release-CI.yml
  • integration_tests/base_routes.py
  • integration_tests/subroutes/__init__.py
  • integration_tests/subroutes/auth_subrouter.py
  • integration_tests/test_async_authentication.py
  • robyn/__init__.py
  • robyn/authentication.py
  • robyn/router.py

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 15, 2026

Merging this PR will not alter performance

✅ 189 untouched benchmarks
🆕 6 new benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 test_inherited_auth_valid_token N/A 2.7 ms N/A
🆕 test_inherited_auth_invalid_token N/A 2.7 ms N/A
🆕 test_async_auth_handler_no_token N/A 2.6 ms N/A
🆕 test_async_auth_handler_invalid_token N/A 2.7 ms N/A
🆕 test_async_auth_handler_valid_token N/A 2.7 ms N/A
🆕 test_inherited_auth_no_token N/A 2.7 ms N/A

Comparing fix/async-auth-handler-support (2988e6a) with main (3e04c65)

Open in CodSpeed

actions/checkout@v3 uses Node.js 16 which reached EOL in 2024.
Also guards the discord notification step against non-tag triggers
and prevents grep from failing the job under set -e when PREV_TAG
is empty (first release) or when filtered log output is empty.

Made-with: Cursor
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.

Authentication handler and async ORM support

1 participant