How to build candidate authentication for a job board
Connect registration, verification, login, explicit refresh, and logout.
A
JTreat authentication as a state machine owned by your app. The SDK performs API operations and token persistence according to your configured storage.
Choose who owns storage
This browser example uses tab-scoped session storage. For an SSR application, use storage: 'nostore' and the SSR session cookie flow instead.
1234567// src/lib/cavuno.browser.tsimport { createBoardClient } from '@cavuno/board';export const board = createBoardClient({board: 'pk_example',auth: { storage: 'session' },});
Persistent browser modes are scoped by board identifier, so two boards on one origin do not share tokens. They remain readable by JavaScript and therefore require normal XSS defenses.
Register and verify a candidate
register stores the returned access and refresh tokens using the configured storage. The application owns the form, verification screen, and navigation.
1234567891011121314151617181920212223import { board } from './cavuno.browser';export async function registerCandidate(input: {email: string;password: string;displayName: string;}) {const session = await board.auth.register({role: 'candidate',method: 'emailpass',...input,});return {user: session.boardUser,needsVerification: !session.boardUser.emailVerified,};}export async function verifyCode(code: string) {await board.auth.verifyEmailWithCode({ code });return board.me.retrieve();}
The emailed magic-link token can instead be sent to board.auth.verifyEmail({ token }). Do not confuse that anonymous token flow with verifyEmailWithCode, which requires the signed-in bearer.
Login, refresh, and logout
The SDK does not refresh automatically after a 401. Make one explicit refresh attempt, retry the protected read once, and return to signed-out state if rotation fails.
123456789101112131415161718192021import { isUnauthorized } from '@cavuno/board';export async function login(email: string, password: string) {await board.auth.login({ email, password });return board.me.retrieve();}export async function loadCurrentUser() {try {return await board.me.retrieve();} catch (error) {if (!isUnauthorized(error)) throw error;await board.auth.refresh();return board.me.retrieve();}}export async function logout() {await board.auth.logout();}
Refresh tokens are single-use. Avoid letting multiple browser requests independently refresh the same expired session. SSR applications should use createSessionRefresher for in-process single-flight rotation.
Handle other entry points
requestMagicLinkandconsumeMagicLinkimplement passwordless login.forgotPasswordalways returns success when accepted, whether or not the email exists.resetPasswordconsumes a single-use token and invalidates existing sessions.getOAuthAuthorizationUrlreturns a provider URL; the app performs navigation.exchangeOAuthconsumes the callback token and stores the returned session.
Validate every returnTo path before redirecting after login or OAuth.
Verify the journey
- Register a new address and render the unverified state.
- Verify by both supported UI paths if you expose both.
- Reload and confirm the selected storage mode behaves as intended.
- Expire the access token and confirm one refresh restores the private read.
- Revoke the refresh token and confirm the app returns to signed-out state.
- Log out and verify
board.me.retrieve()no longer succeeds.
Production notes
- SSR apps must keep tokens in an
HttpOnlycookie. - Configure that session cookie with
HttpOnly,Secure, and an appropriateSameSitepolicy. Protect state-changing cookie-authenticated requests against CSRF; cookie flags do not replace CSRF protection. - Give email, current-password, and new-password controls visible labels and correct
autocompletevalues so password managers and assistive technology can identify them. - Preserve the intended return path without accepting open redirects.
- Display validation details near the corresponding field and log the API request ID for unexpected failures.
- If logout fails before server revocation, the SDK retains local tokens so the application can retry. Decide separately whether to offer a force-local-logout action.
See the Auth reference for every method and response type.