---
title: Password Authentication
project: Authaz
updated: 2026-04-29T17:34:53.910Z
---


# Email/Password

Email + password is the default sign-in method. It's enabled the moment you create an application — no extra configuration required to ship a working login flow.

```bash
# A user signs up via Universal Login — no API call needed from your side.
# Optionally, configure the policy programmatically:
curl -X PUT https://your-app.authaz.io/api/v1/applications/{appId}/auth/password \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "policy": {
      "minLength": 12,
      "requireUppercase": true,
      "requireNumber": true,
      "requireSymbol": false
    },
    "mfaRequirement": "optional"
  }'
```

## Configuration

Open **Dashboard → Application → Authentication → Password**, or call the policy endpoint above.

> Whether this config is shared across every tenant or scoped per tenant is controlled by the **Isolated Auth Stack** switch on *Settings → General → Tenant Customization*. With **Shared** auth (default), one password policy applies to every tenant. With **Isolated** auth, the Authentication tab shows a tenant picker and each tenant gets its own policy. See [Tenancy Customization](../tenancy-customization.md#isolated-auth-stack).

| Setting | What it controls |
|---------|-----------------|
| **Policy type** | Pick a preset (`good`, `excellent`, `fair`) or `custom`. Presets are recalibrated against current best practice; `custom` exposes every knob below. |
| **Minimum length** | Default `12`. Below 8 is rejected outright. |
| **Maximum length** | Default `128`. Set high enough to allow passphrases; lower only if a downstream system truly can't handle longer values. |
| **Require uppercase / lowercase / numbers / special characters** | Per-class booleans. Composability is friendlier than mandating all four. |
| **Check password breach** | Validates against the HaveIBeenPwned k-anonymity API. Only the first 5 hex characters of the SHA-1 hash leave your infrastructure. |
| **Password history count** | How many previous passwords are remembered to prevent re-use. Default `5`. `0` disables history. |
| **Password reset token expiry** | How long a reset code remains valid (minutes). Default `60`. |
| **Require old password on reset** | When `true`, the reset flow asks for the current password too — useful when the "forgot password" entrypoint is misused as a password change. Default `false`. |
| **MFA requirement** | `disabled`, `optional` (user opts in), or `required` (cannot sign in without it). See the [MFA page](./mfa.md) for the full enforcement options. |
| **Account lockout** | Failed-attempt threshold and lockout duration. Defaults: 5 attempts → locked for 15 minutes. |
| **Session policy** | Idle timeout, max session duration, concurrent-session limit. Configured in [Authentication Settings](./settings.md#session-policy). |
| **Signup** | Open, invitation-only, or domain-allowlist. Configured on the [Signup page](./signup.md). |

Any setting changed in the dashboard is reflected immediately — no redeploy.

## MFA (TOTP)

When MFA is `required` or the user opts in, they register a TOTP authenticator (Google Authenticator, 1Password, Authy, etc.) on their first signed-in visit:

1. Authaz shows a QR code and a base-32 secret.
2. The user scans it and enters the rolling 6-digit code to confirm.
3. Authaz issues a set of **emergency recovery codes** — show the user once, never again.

On every subsequent login, Universal Login prompts for the TOTP code after the password step. Recovery codes work as a backup.

Reset MFA for a user (e.g. they lost their phone):

```bash
curl -X POST https://your-app.authaz.io/api/v1/users/{userId}/mfa/reset \
  -H "X-API-Key: $AUTHAZ_API_KEY"
```

The user is forced to re-enroll on next login.

## Password reset

The flow is fully hosted — your app never sees a plaintext password. Universal Login owns it end-to-end:

1. User clicks **Forgot password** on the login page.
2. They enter their email; Authaz sends a reset code.
3. They enter the code on the reset page; Authaz lets them set a new password (which must satisfy the active policy).

You can also kick this off from your backend:

```bash
curl -X POST https://your-app.authaz.io/auth/password/forgot-password \
  -H "Content-Type: application/json" \
  -d '{
    "applicationId": "app_01h...",
    "email": "user@example.com"
  }'
```

The response is intentionally `200 OK` whether or not the email exists — leaking that information is an enumeration vulnerability.

## Account lockout

When a user fails too many login attempts in a row, they're locked out for the configured window. Authaz returns:

```json
{ "error": "account_locked", "retryAfter": 900 }
```

`retryAfter` is in seconds. To unlock manually (e.g. after verifying identity through support):

```bash
curl -X POST https://your-app.authaz.io/api/v1/users/{userId}/unlock \
  -H "X-API-Key: $AUTHAZ_API_KEY"
```

## Breach detection

If you enable breach detection in the policy, every signup and password reset is checked against the HaveIBeenPwned k-anonymity API. Authaz only sends the first 5 hex characters of the SHA-1 hash, so the plaintext never leaves your infrastructure. Compromised passwords are rejected with:

```json
{ "error": "password_breached", "message": "This password has appeared in a known data breach." }
```

## Inviting users (no self-signup)

When signup is `invitation-only`, you create users by sending an invitation:

```bash
curl -X POST https://your-app.authaz.io/api/v1/invitations \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "newhire@yourcompany.com",
    "roleIds": ["role_member"]
  }'
```

The user receives an email with a one-time link, sets their password on Universal Login, and is automatically assigned the listed roles.

## Suspending and re-activating users

```bash
# Block sign-in (does not delete data)
curl -X POST https://your-app.authaz.io/api/v1/users/{userId}/suspend \
  -H "X-API-Key: $AUTHAZ_API_KEY"

# Allow sign-in again
curl -X POST https://your-app.authaz.io/api/v1/users/{userId}/activate \
  -H "X-API-Key: $AUTHAZ_API_KEY"

# Force logout from every device, immediately
curl -X POST https://your-app.authaz.io/api/v1/users/{userId}/sessions/revoke \
  -H "X-API-Key: $AUTHAZ_API_KEY"
```

Suspended users can no longer sign in or refresh tokens; existing sessions remain valid until their access tokens expire (default 15 min). Pair with `sessions/revoke` if you need an immediate logout.

## Next steps

- [Magic Link](./magic-link.md) — passwordless, often paired with password as a backup.
- [Passkey](./passkey.md) — phishing-resistant, replaces password for many users.
- [cURL quickstart](../quickstart/curl.md) — see a password sign-in end-to-end.
