Kyndex

Authentication

Register, log in, bind sessions, and refresh tokens using OPAQUE authentication.

Literal uses OPAQUE for password authentication. OPAQUE lets a client prove knowledge of a password without sending the password to Literal.

Authentication has three stages:

  1. Register — create an OPAQUE registration record and store encrypted client key material.
  2. Log in — complete the OPAQUE login handshake and receive a pending access token.
  3. Bind the session — derive and submit a refresh token to activate the session.

The server never receives the user’s password or raw email. Full endpoint schemas live in the API Reference.

Loading diagram…

Authentication Flow

Literal authentication combines OPAQUE, OPRF-derived login buckets, client-side key material, and session binding.

At a high level:

  • The client derives a privacy-preserving login bucket before registration or login.
  • The client uses OPAQUE to register or authenticate without sending the password.
  • Literal stores only the OPAQUE registration record and encrypted client key material.
  • Login returns a pending access token.
  • The client binds the session with a refresh token derived through OPRF.
  • Once bound, the session can be used for document, grant, and search operations.

OPAQUE requires a client-side library for the cryptographic handshake. Use the API Reference for exact request and response schemas.

Before Registration: Derive The Login Bucket

Registration and login both require a login_bidx, a privacy-preserving login bucket derived through OPRF.

This prevents Literal from receiving the raw email during authentication. The client blinds the login identifier, Literal evaluates the blinded value, and the client unblinds the result to produce the bucket index used during registration and login.

See Deriving The Login Bucket for the step-by-step flow.

Register An Account

Registration is a two-step OPAQUE handshake.

The client starts registration by sending:

  • the derived login_bidx
  • an OPAQUE registration request generated by the client library

Literal returns the OPAQUE registration response.

The client then finalizes the registration locally. During this step, the client creates the OPAQUE registration record, derives local key material, encrypts private keys, and prepares encrypted account metadata.

The finish step stores:

  • the OPAQUE registration record
  • encrypted email metadata
  • public keys
  • encrypted private key material
  • optional recovery material

Literal does not receive the user’s password or raw email. Private keys and sensitive account metadata are encrypted before being sent to Literal.

Endpoint sequence:

  • POST /auth/opaque/register-start
  • POST /auth/opaque/register-finish

See the API Reference for complete request fields and response bodies.

Log In

Login is also a two-step OPAQUE handshake.

The client starts login by sending:

  • the derived login_bidx
  • an OPAQUE login request generated by the client library

Literal returns a login session ID and a padded list of candidate OPAQUE records.

Try every login candidate

Literal pads the candidate list with dummy entries to prevent bucket-occupancy oracle attacks. The client must attempt every candidate and only then submit the successful candidate_index. Short-circuiting on the first success can leak the successful position through timing.

After the client identifies the valid candidate, it finishes the OPAQUE login locally and submits:

  • the login session ID
  • the successful candidate index
  • the OPAQUE finish message
  • client-derived session tokens

The session tokens are generated client-side:

  • owner_token identifies personal documents without exposing the account identity.
  • user_member_token identifies entity memberships.
  • revocation_token supports identity-free session revocation.

A successful login returns an access token, refresh token material, encrypted user key material, and entity membership data. The access token returned at this stage is pending until the session is bound.

Endpoint sequence:

  • POST /auth/opaque/authenticate-start
  • POST /auth/opaque/authenticate-finish

See the API Reference for complete request fields and response bodies.

Bind The Session

The access token returned by login starts as a pending token. Pending tokens cannot access document, grant, or search operations.

To activate the session, the client derives a refresh token through OPRF evaluation and submits it to bind the session. Literal then returns an active access token and invalidates the pending token.

Endpoint sequence:

  • POST /auth/session/refresh-eval
  • POST /auth/session/bind

After binding succeeds, use the active access token for authenticated API requests.

If session binding fails after the pending session is consumed, the session is lost and the user must log in again.

What To Store After Login

After a successful login and session bind, store the following client-side:

  1. Access token — Use for authenticated API requests until it expires.
  2. Refresh token — Store securely and rotate it whenever the session is refreshed.
  3. Session tokens — Keep owner_token, user_member_token, and revocation_token available for document operations, entity operations, and logout.
  4. Private key material — Decrypt private keys with the User Master Key only when needed, keep decrypted keys in memory only, and use the required AEAD context from Key Material And Key Lifecycle.

Do not store the user’s password. Do not send raw email or plaintext private keys to Literal.

Token Lifecycle And Refresh

Access tokens expire after 15 minutes. Refresh tokens are valid for 12 hours and are single-use.

When refreshing a session, include owner_token and user_member_token to keep the session unlocked for document operations. Omitting them creates a locked session: authenticated, but unable to access document operations.

Each refresh rotates the refresh token. Discard the old refresh token after a successful refresh and store the new one.

Use:

  • POST /auth/tokens/refresh to rotate the access and refresh tokens.
  • DELETE /sessions/current to invalidate the current session.
  • DELETE /sessions to revoke every active session for the account.

See Session Lifecycle for session states, refresh behavior, locked sessions, and logout semantics.

Next Steps

Last updated on

On this page