Auth Methods
Kyqu supports multiple authentication methods that can be enabled/disabled per project.
Available Methods
| Method | Status | Description |
|---|---|---|
| Email/Password | ✅ Done | Standard email + password authentication |
| Email Verification | ✅ Done | Require email confirmation before granting access |
| Password Reset | ✅ Done | Reset forgotten passwords via email |
| Magic Link | ✅ Done | Passwordless sign-in via emailed link |
| TOTP 2FA | ✅ Done | Time-based one-time passwords with authenticator apps |
| Passkeys (WebAuthn) | ✅ Done | FIDO2 WebAuthn with platform authenticators |
| Social Login (OAuth) | ✅ Done | Sign in with Google, GitHub |
| OIDC / ID Tokens | ✅ Done | OpenID Connect Discovery and RS256 ID tokens |
| SMS | 📋 Planned | SMS-based verification codes |
| SSO | 📋 Planned | SAML/OIDC single sign-on as relying party |
Email/Password
Default auth method. Users sign up with email and password:
const { user, session } = await kyqu.signup({
email: "user@example.com",
password: "correct-horse-battery-staple"
});
Password requirements:
- Minimum length configurable per project (default: 10 characters)
- scrypt hashed (not stored in plaintext)
- Compared using constant-time
timingSafeEqual
Email Verification
When enabled, signup creates a user account without a session. The user must verify their email before logging in:
// Signup — no session returned
const { user, session: null, verificationRequired: true } = await kyqu.signup({...});
// Verification email is sent automatically
// User clicks link in email → email verified
// Now they can log in
const { user, session } = await kyqu.login({...});
Verification flow:
- User signs up → verification email sent
- User clicks link → browser hits GET
/verify-email/confirm?token=... - If
email_verified_urlconfigured → redirect to project's UI - If no redirect URL → JSON response with user data
Password Reset
Users can reset forgotten passwords via email:
// Request reset
await kyqu.requestPasswordReset("user@example.com");
// Email received → user clicks link
// Link points to GET /password-reset/confirm?token=...
// If password_reset_url configured → redirect with token as query param
// Project's UI collects new password and POSTs to confirm
const { user, session } = await kyqu.confirmPasswordReset({
token: "token-from-email",
password: "new-password-42"
});
Magic Link
Passwordless sign-in via email:
// Request magic link
await kyqu.requestMagicLink("user@example.com");
// Email received → user clicks link
// GET /magic-link/confirm?token=...
// If login_url configured → redirect with session token
// Session token is in query param: ?token={raw-session-token}
TOTP 2FA
Time-based one-time passwords using authenticator apps (Google Authenticator, Authy, 1Password, etc.):
// Step 1: Start enrollment (user must be logged in)
const { enrollmentUrl } = await kyqu.enrollTotp(sessionToken);
// enrollmentUrl: "otpauth://totp/..."
// Render enrollmentUrl as QR code for the user to scan
// Step 2: Confirm enrollment
const { backupCodes } = await kyqu.confirmTotp(sessionToken, "123456");
// Returns 8 one-time backup codes — show immediately
// Step 3: Login with TOTP
const { user, session } = await kyqu.login({
email: "user@example.com",
password: "correct-horse-battery-staple",
totpCode: "123456" // or backupCode: "abcd-efgh-ijkl-mnop"
});
TOTP Implementation Details:
- RFC 6238 compliant
- HMAC-SHA1, 30-second window
- ±1 window tolerance (90-second grace period)
- 20-byte Base32-encoded secrets
- Backup codes: 8 codes, XXXX-XXXX-XXXX format, hashed in database
Backup Codes
When TOTP is enabled, the user receives 8 one-time backup codes. Each code can be used once for login when the authenticator app is unavailable.
Passkeys (WebAuthn)
Passkeys allow users to authenticate with platform biometrics (Touch ID, Face ID, Windows Hello) or cross-device credentials.
How it works:
Kyqu handles the server side of the WebAuthn ceremony. The client SDK exposes methods that pair with navigator.credentials.create() and navigator.credentials.get():
Registration
// Step 1: Get registration options from server
const options = await kyqu.getPasskeyRegistrationOptions(token);
// Step 2: Create credential via browser WebAuthn API
const credential = await navigator.credentials.create({
publicKey: options
});
// Step 3: Verify and store the credential
await kyqu.registerPasskey(token, credential, "My MacBook Pro");
Authentication
// Step 1: Get authentication options
const options = await kyqu.getPasskeyAuthenticationOptions();
// Step 2: Get assertion from browser
const assertion = await navigator.credentials.get({
publicKey: options
});
// Step 3: Verify and receive session
const { user, session } = await kyqu.authenticateWithPasskey(assertion);
Credential Management
// List registered passkeys
const { passkeys } = await kyqu.listPasskeys(token);
// Delete a passkey
await kyqu.deletePasskey(token, credentialId);
Implementation details:
- FIDO2 WebAuthn Level 2 compliant
- Supported platform authenticators: macOS Touch ID, Windows Hello, Android biometric, iOS Face ID/Touch ID
- Cross-device authentication via QR code (hybrid transport)
- Credentials stored as CBOR-encoded public keys with credential ID
- Challenge generated per ceremony with TTL and one-time use
Social Login (OAuth)
Kyqu supports OAuth 2.0 social login via Google and GitHub identity providers.
Setup
Configure OAuth providers in the admin dashboard per project:
- Register your app with the provider (Google Cloud Console / GitHub OAuth Apps)
- Set the redirect URI to:
https://auth.example.com/api/projects/{projectId}/auth/oauth/{provider}/callback - Enter client ID and client secret in Kyqu admin dashboard
Authentication Flow
// Step 1: Redirect user to provider's consent screen
const authorizeUrl = kyqu.getOAuthAuthorizeUrl("google");
window.location.href = authorizeUrl;
// Step 2: After callback, user is either:
// - Logged in (existing linked account)
// - Prompted to link to existing email/password account (new OAuth user)
Account Linking
When a user signs in with OAuth for the first time:
- If the email matches an existing project user, the OAuth identity is linked to that account
- If the email is new, a new user is created with the OAuth identity attached
Implementation Details
- Authorization code flow with PKCE
- State parameter with CSRF protection
- Provider configurations stored per project in
project_oauth_providerstable - OAuth states tracked in
project_oauth_stateswith TTL - Account links stored in
project_user_oauth_links