POST/api/auth/loginPublic

Log in with email and password

Verifies the credentials and starts a PKCE authorization-code grant for client_app_id: on success the authorization code is bound to the code challenge, the redirect_uri, the granted scopes and the nonce, and the auth server's HTTP-only session cookie is set. Accounts with a verified second factor get an mfa_required challenge instead (complete it at POST /api/auth/mfa/verify). A third-party client_app_id gets email_verification_required (session cookie set, no code) while the account's e-mail address is unverified and the require_email_verification_for_third_party_apps server setting is on. Wrong credentials and unknown accounts answer the same 401. Rate limited per IP + e-mail (a sliding window plus a lockout counter of failed attempts).

operationId post_api_auth_loginAuthentication

Authentication & permissionsPublic

Anyone — no credentials required

Accepted credentials
None required
Notes
Credentials travel in the body. An existing auth server session cookie is only used to refuse signing in as a different user.

Request body

Required — The body is parsed by the handler itself so its error format stays stable.

application/json
LoginRequestUnknown keys are rejected.
PropertyTypeDescription
credentials*LoginCredentials
email*string (email)

Account e-mail address; trimmed and lower-cased before lookup

password*string

Account password (must satisfy the password policy)

minLength: 10maxLength: 255

client_app_id*string

Client application the authorization code is issued for

minLength: 2maxLength: 64pattern: ^[a-z0-9_-]*$

code_challenge*string

PKCE S256 code challenge (RFC 7636) the authorization code is bound to

minLength: 43maxLength: 1024

challenge_time*number

Unix epoch milliseconds when the PKCE verifier was created; stale challenges are refused at redemption

minimum: 0

redirect_uristring (uri) | null (uri) | null

OAuth2 redirect_uri bound to the authorization code. Required for third-party client apps and must be registered for the app; omitted (or null) only for the auth server's own /account flow.

noncestring | null | null

OIDC login nonce (OIDC Core §3.1.2.1), echoed in the id_token at redemption. Optional.

minLength: 1maxLength: 512pattern: ^[\x20-\x7E]+$

scopestring

Requested scopes, space delimited (RFC 6749 §3.3). The server re-derives the granted subset; absent, or naming no supported scope, is a plain OAuth 2.1 grant without an id_token.

minLength: 1maxLength: 1024pattern: ^[\x21\x23-\x5B\x5D-\x7E]+(?: [\x21\x23-\x5B\x5D-\x7E]+)*$

resourcestring

RFC 8707 resource indicator of the authorization request: an API server id, or the URL of one of its registered domains. When it names an API server this client app may use, the requested scope values that API server defines (its API scopes) are granted too, bound to it; otherwise it is ignored.

minLength: 1maxLength: 2048

JSONExample
"credentials"
"email""jane@example.com"
"password""string"
"client_app_id""my-web-app"
"code_challenge""string"
"challenge_time"1.5
"redirect_uri""https://example.com"
"nonce""string"
"scope""openid profile email"
"resource""https://api.example.com/mcp"

Responses

application/json
AuthenticateSuccessResult

Discriminated on kind: authenticated, mfa_required or email_verification_required.

JSONExample
"kind""authenticated"
"success"true
"message""string"
"authorization_code""string"

Example request

bashcurl
curl -X POST 'https://auth.schemavaults.com/api/auth/login' \
  -H 'Content-Type: application/json' \
  -d '{
  "credentials": {
    "email": "jane@example.com",
    "password": "string"
  },
  "client_app_id": "my-web-app",
  "code_challenge": "string",
  "challenge_time": 1.5,
  "redirect_uri": "https://example.com",
  "nonce": "string",
  "scope": "openid profile email",
  "resource": "https://api.example.com/mcp"
}'