Skip to content

OAuth rework#437

Open
augustuswm wants to merge 90 commits into
mainfrom
oauth-rework
Open

OAuth rework#437
augustuswm wants to merge 90 commits into
mainfrom
oauth-rework

Conversation

@augustuswm
Copy link
Copy Markdown
Collaborator

@augustuswm augustuswm commented May 7, 2026

A bunch of work that restructures how we do OAuth.

  1. Adds support for PKCE (Proof Key for Code Exchange) and secret-less code flows
  2. Adds Zendesk as a backend IdP
  3. Adds support for acquiring the underlying IdP access token that is generated (gated behind a permission)
  4. Introduces a crate v-cli-sdk with prebuilt commands for authentication and configuration that v-api based CLI applications can embed
  5. Introduces PKCE based code flow for CLI authentication
  6. A number of spec adherence issues fixed

Copy link
Copy Markdown
Contributor

@notpeter notpeter left a comment

Choose a reason for hiding this comment

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

I took a stab at reviewing this. Most of my comments are style-related, feel free to apply/ignore/fix later/never/etc.

Oh yeah and the date/ are wrong on migrations (note 2026).
2025-01-01, 2025-01-02, 2025-05-18 -> 2026-05-18_000001 etc.

Agent also identified a potential cli deadlock that figured I'd mention, which we're unlikely to hit, but would by definition be difficult to debug (no error message).

deadlock on cli errors

The CLI PKCE callback path can deadlock on error callbacks. The proxy consumes the single-use callback before invoking it, but the handler only sends on token_tx after successful parsing and code exchange. If the browser
returns error=access_denied, a malformed callback, or a CSRF mismatch, the handler returns Err without notifying the waiting login task, and the caller remains blocked on token_rx indefinitely.

Suggested fix: make the callback always complete the one-shot, including failure cases. The simplest approach is to catch all callback errors inside the closure and send Err(...) through token_tx before returning an HTTP
response to the browser. Optionally, also handle error callbacks explicitly and show a user-friendly failure page instead of treating them as missing code.

Comment thread v-api/src/context/auth.rs
Comment thread v-api/src/context/mod.rs
Comment thread v-api/src/context/mod.rs
mappers: Vec<EphemeralMapperConfig>,
#[cfg(feature = "sagas")]
saga: Option<(TypedUuid<SagaExecNodeId>, Option<Logger>)>,
additional_builtin_permissions: Vec<T>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

style: Perhaps worth adding a doc comment here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the note. I need to rework this actually. Given some permission changes, this needs to change as well.

Comment thread v-api/src/endpoints/login/magic_link/client.rs Outdated
Comment thread v-api/src/endpoints/login/oauth/flow/code.rs
Comment thread v-cli-sdk/src/cmd/auth/login.rs Outdated
Comment thread v-api/src/endpoints/login/oauth/flow/device_token.rs Outdated
Comment thread v-cli-sdk/src/cmd/auth/oauth/device.rs
Comment thread v-api/src/endpoints/login/oauth/flow/device_token.rs Outdated

// Check expiration - An attempt without an expiration is by default
// expired.
// TODO: Change expires_at to be non-optional. A login attempt should always
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is now a reasonable time to have a migration that sets a default value (0) for any existing rows and updates the database to be non-nullable and drops the Option<> from expired_at in LoginAttemptModel and LoginAttempt?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I think I want to put that into a separate PR at least. I'm still not 100% on if this should be an option or not.

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.

2 participants