Skip to content

feat: passwordless support - #153

Open
rmad17 wants to merge 7 commits into
mainfrom
feat/passwordless-support
Open

feat: passwordless support#153
rmad17 wants to merge 7 commits into
mainfrom
feat/passwordless-support

Conversation

@rmad17

@rmad17 rmad17 commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Changes

Added

  • Adds ServerClient.passwordless for embedded passwordless flows: Email OTP, SMS OTP (via /passwordless/start + the passwordless OTP token grant), and Email Magic Link (SDK-owned state/redirect_uri, transaction
    storage for callback completion).
  • Creates server-side sessions after successful OTP verification and magic-link callback completion, reusing the shared _persist_session_from_token_response path (issuer/audience/session-expiry checks already
    enforced there, not new in this PR).
  • Handles mfa_required during passwordless OTP verification; MFA can be completed into a new SDK session via mfa.verify(..., persist=True). Known limitation, not yet fixed: this MFA-initiated session-creation
    path does not run organization-claim validation, unlike every other session-creating path in the SDK. Flagging for reviewer visibility — no organization-scoped passwordless/MFA usage should ship until this is
    closed.
  • Adds typed passwordless option models (StartPasswordlessEmailOptions, StartPasswordlessSmsOptions, VerifyPasswordlessOtpOptions) and passwordless-specific typed errors (PasswordlessStartError,
    PasswordlessVerifyError), including retry_after (from Retry-After), raw non-JSON error body capture (truncated), and 429 → too_many_requests mapping.
  • Enforces E.164 validation for SMS phone numbers.
  • Adds safeguards so magic-link callers cannot override SDK-owned protocol values (redirect_uri, response_type, state); supports caller-supplied scope on magic link, re-injecting openid when omitted.
  • Removes organization support from passwordless start/verify. The field existed but always failed in practice — the server ignores it on this grant, and the SDK's own claim validation then hard-raised on the
    missing claim. Removed rather than fixed, since there was no working path to preserve. Flag if organization on passwordless was already relied on anywhere.
  • Fixes session sid sourcing for all interactive logins, not just passwordless — complete_interactive_login previously fell back to a random sid whenever user_info was absent, even when the ID token carried a sid
    claim. It now prefers the ID token's sid claim, then user_info, then random. This affects every existing interactive-login session, since OIDC back-channel logout matches by sid and previously could silently
    fail to target sessions created this way.
  • Adds Passwordless documentation (examples/Passwordless.md) and README links.

Testing

  • This change adds unit test coverage
  • This change adds integration test coverage
  • This change has been tested on the latest version of the platform/language or why not

Checklist

@rmad17
rmad17 requested a review from a team as a code owner August 8, 2026 05:33

def __init__(self, code: str, message: str, cause=None, retry_after: Optional[int] = None):
super().__init__(code, message, cause, retry_after)
self.name = "PasswordlessStartError"

def __init__(self, code: str, message: str, cause=None, retry_after: Optional[int] = None):
super().__init__(code, message, cause, retry_after)
self.name = "PasswordlessVerifyError"
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