Skip to content

Log in with email and password.

POST
/v1/auth/login
curl --request POST \
--url https://api.opdns.io/v1/auth/login \
--header 'Content-Type: application/json' \
--data '{ "email": "[email protected]", "password": "example", "totp_code": "example", "recovery_code": "example" }'

Sets the opdns_session cookie (HttpOnly, Secure, SameSite=Lax) and rotates any previous session. When the account has TOTP enabled, totp_code (or recovery_code) is required: 401 second_factor_required when missing, invalid_second_factor when wrong or reused (attempts limited per account). Outside dev, an account with neither TOTP nor a passkey past its grace period (session.mfa_deadline) gets a session with restricted: true, usable only to enrol one. A sign-in from a new browser and network emails a notice.

Failed attempts (unknown address, wrong password, wrong second factor) slow the next attempt from the same client IP or for the same address: 100 ms after one failure, doubling to at most 5 s; a success clears the address’s delay. Ten failures on an account within an hour email its owner, at most once an hour. Passkey sign-in is not delayed.

Media typeapplication/json
object
email
required
string format: email
password
required
string
totp_code

Required when the account has TOTP enabled (or send recovery_code).

string
recovery_code

A single-use recovery code, in place of totp_code.

string
Examplegenerated
{
"email": "[email protected]",
"password": "example",
"totp_code": "example",
"recovery_code": "example"
}

Logged in.

Media typeapplication/json
object
account
required
object
id
required
string format: uuid
org_id
required
string format: uuid
role
required
string
Allowed values: owner admin member
email
required
string format: email
email_verified_at
string | null format: date-time
plan
required
string
mfa
required
boolean
created_at
required
string format: date-time
is_admin

Operator account; may hold the admin scope.

boolean
deletion_requested_at
string | null format: date-time
deletion_due_at

Set while a deletion is pending; the account is erased at this time unless cancelled.

string | null format: date-time
session
required
object
auth_method
required
string
Allowed values: password password_totp password_recovery_code passkey
restricted
required

A restricted session may only enrol a second factor (TOTP setup/confirm, passkey registration, GET /v1/auth/me, logout); every other call is 403 mfa_enrolment_required. Set for password-only sign-in after the grace period, outside dev.

boolean
mfa_deadline
required

When password-only sign-in becomes restricted; null once a second factor exists, and in dev.

string | null format: date-time
Example
{
"account": {
"role": "owner"
},
"session": {
"auth_method": "password"
}
}
Set-Cookie
string

Malformed request.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
Example
{
"type": "https://opdns.io/problems/bad_request",
"title": "Bad Request",
"status": 400,
"code": "bad_request",
"detail": "invalid JSON body",
"request_id": "5f2c9a0e7b1d4c38"
}

Not authenticated.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
Example
{
"type": "https://opdns.io/problems/unauthenticated",
"title": "Unauthorized",
"status": 401,
"code": "unauthenticated",
"detail": "authentication required",
"request_id": "5f2c9a0e7b1d4c38"
}

Rate limited (rate_limited).

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
Example
{
"type": "https://opdns.io/problems/rate_limited",
"title": "Too Many Requests",
"status": 429,
"code": "rate_limited",
"detail": "too many requests",
"request_id": "5f2c9a0e7b1d4c38",
"retry_after": 6
}
Retry-After
integer