kavachOS
Authentication

Username and password

Register and sign in with a unique username and password instead of email.

The usernamePassword plugin lets users pick a username at registration and sign in with it. It is a drop-in alternative to the email-password plugin for apps where email addresses are not the primary identity.

Setup

lib/kavach.ts
import { createKavach } from 'kavachos';
import { usernamePassword } from 'kavachos/plugins/username-password'; 

const kavach = await createKavach({
  database: { provider: 'postgres', url: process.env.DATABASE_URL! },
  secret: process.env.KAVACH_SECRET!,
  baseUrl: 'https://auth.example.com',
  plugins: [
    usernamePassword({ 
      minUsernameLength: 3, 
      maxUsernameLength: 32, 
      allowedPattern: /^[a-z0-9_-]+$/i, 
    }), 
  ],
});

Mount the handler the same way as any other plugin — see adapters.

Sign up

POST /auth/sign-up

Sign up (client)
const res = await fetch('/auth/sign-up', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'ada_lovelace', 
    password: 'correct horse battery',
    name: 'Ada Lovelace', // optional display name
  }),
});

const { user, token } = await res.json();

Error codes

CodeStatusMeaning
USERNAME_TAKEN409Username is already registered
USERNAME_INVALID422Does not match allowedPattern
USERNAME_TOO_SHORT422Below minUsernameLength

Sign in

POST /auth/sign-in

Sign in (client)
const res = await fetch('/auth/sign-in', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'ada_lovelace', 
    password: 'correct horse battery', 
  }),
});

const { user, session } = await res.json();

Returns 401 with code INVALID_CREDENTIALS for any bad username/password combination. The response never reveals whether the username exists.

Change username

POST /auth/change-username

Requires an active session. Usernames must still be unique after the change.

Change username (client)
const res = await fetch('/auth/change-username', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    newUsername: 'ada_v2', 
    password: 'correct horse battery', // current password required
  }),
});

Configuration reference

Prop

Type

On this page