Skip to content
rw3iss Auth

Login & Registration

How a basic app signs users up, signs them in and out, using the @rw3iss/auth-client SDK directly (no UI components). All session state — tokens, refresh scheduling, cross-tab sync — is owned by the client core; you just call the modules.

Reference: AuthModule · AccountModule · AuthClient

Instantiate the client

One client per app, created once at boot. appCode is your app’s code in the auth-server’s app registry — it scopes every issued token.

import { createAuthClient } from '@rw3iss/auth-client';
const client = createAuthClient({
apiBaseUrl: 'https://auth.ryanweiss.net/api/v1',
appCode: 'my-app',
});
// Wait for the boot check (validates any cached session).
await client.ready();

Register a new account

const result = await client.auth.register({
email: 'new@example.com',
password: 'Str0ngPass!',
firstName: 'New',
lastName: 'User',
// appCode defaults to the client's configured app code.
});
console.log(result.user.id, result.verification_email_sent);

The server applies the app’s registration policy (allowed email domains / auth methods), places the user in the app’s default pool, and fires any configured webhooks.

Tip: render an accurate form before submit by reading the public policy — no token required:

const policy = await client.auth.getRegistrationPolicy();
// policy.allowed_email_domains, policy.allowed_auth_methods, …

Log in

const res = await client.auth.login({
email: 'new@example.com',
password: 'Str0ngPass!',
rememberMe: true, // 30d refresh token instead of 7d
});
if (res.requires_2fa) {
// Account has TOTP active — re-submit with the code.
const code = await promptUserForTotp();
await client.auth.login({ email, password, twoFactorCode: code });
}
client.auth.isAuthenticated(); // true
client.auth.getCurrentUser(); // decoded from the access token
await client.auth.whoami(); // server-authoritative /auth/me

After login the SDK persists the token pair, schedules refresh ahead of expiry, and broadcasts the session to other tabs. Subscribe to lifecycle events instead of polling:

client.on('logged_out', () => router.push('/login'));
client.on('session_expired', () => router.push('/login'));
client.on('token_refreshed', () => {/* metrics, etc. */});

Log out

await client.auth.logout(); // revoke THIS session's refresh token
await client.auth.logoutAll(); // revoke EVERY session (all devices) +
// bump the server token-version so
// outstanding access tokens die immediately

Account self-service

Everything the signed-in user does to their own account lives on client.account:

// Password reset (anonymous — server is silent on unknown emails)
await client.account.requestPasswordReset('new@example.com');
await client.account.resetPassword(tokenFromEmail, 'NewStr0ngPass!');
// Change password while signed in
await client.account.changePassword('Str0ngPass!', 'NewStr0ngPass!');
// Email verification
await client.account.verifyEmail(tokenFromEmail);
await client.account.resendVerificationEmail('new@example.com');
// Two-factor (TOTP)
const { provisioningUri, secret } = await client.account.setupTwoFactor();
// render provisioningUri as a QR code, then:
await client.account.enableTwoFactor(firstCodeFromApp);

See also