Skip to content

OIDC deployments cannot authorize a third-party application: the device grant is accounts-only #81

Description

@jan21deepak

What's wrong

create_device_auth_router refuses to build unless auth_provider._source == "accounts", and app.py gates the /oauth/* mount the same way. So on an OIDC deployment the RFC 8628 device-authorization grant does not exist.

The stated reasoning is that OIDC deployments delegate login to the IdP via the cli-ticket flow and therefore never need the grant. That covers a CLI logging a human in. It does not cover a third-party application asking to act as a user, which is what the grant is for.

Why the cli-ticket flow is not a substitute

/auth/cli-login hands back the server's own session JWT. Compared with a delegated token from the device grant it has:

device grant cli-ticket
scope claim (path allowlist)
grant_id → revocation denylist
act provenance (which app acted)
Rotating refresh token
Absolute grant lifetime

Everything that makes a token safe to hand to an application is exactly what it lacks. An OIDC operator's only option today is to give an external client full account authority with no revocation handle.

header mode is genuinely excluded — identity is asserted by an upstream proxy, so there is no session to delegate from. But oidc mints the same HS256 session cookie accounts does, and UnifiedAuthProvider._check_cookie already picks between the two configs identically.

A second, quieter problem

The consent page's anti-phishing gate requires a login performed after the grant began (session iatgrant.created_at), and bounces a stale session through the login page with reauth=1.

reauth=1 is honoured only by the accounts SPA login form. /auth/login never read the parameter. So simply widening the mount condition would produce:

stale session → bounce /auth/login?reauth=1
   → IdP recognises its own session
   → silent redirect back
   → callback mints a session with a fresh iat
   → gate satisfied, user proved nothing

No error, no failing test — the control disappears while still appearing to be there. Any fix that mounts the grant under OIDC has to address this at the same time, or it ships a security regression that passes CI.

Impact

Self-hosted OIDC deployments cannot safely integrate any external client — Slack, CI bots, code-review bots — without handing over an unscoped, unrevocable session token.

Proposed fix

Mount the grant for oidc as well as accounts, and make the re-authentication demand real under OIDC (prompt=login + max_age=0, with the returned auth_time verified rather than assumed).

PR: omnigent-ai#4304


Imported from the parent repository for autonomous engineering evaluation.

Source issue: omnigent-ai#4476

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