Auth namespace

Reference for registration, login, token rotation, verification, password reset, magic links, and OAuth.

board.auth creates and manages candidate or employer sessions for one board. It uses a short-lived bearer access token and an opaque, single-use refresh token. The SDK never navigates and never performs a hidden refresh after a 401—your application owns those decisions.

Session result

Registration, login, refresh, magic-link consumption, and OAuth exchange resolve a BoardAuthSession:

FieldTypeMeaning
object'board_auth_session'Stable result discriminator
accessTokenstringBearer JWT, valid for one hour
refreshTokenstringSingle-use token, valid for 30 days until used or revoked
expiresAtnumberAccess-token expiry in epoch milliseconds
boardUserBoardUserThe authenticated user on this board

Storage and persistence

Methods that return a session also write its access and refresh tokens to the client’s configured auth.storage before resolving.

  • Browser clients default to memory; choose session or local explicitly if the session must survive longer.
  • Server clients default to nostore. Keep the returned pair in an application-owned httpOnly cookie and pass authorization per call.
  • refresh replaces both stored tokens with the rotated pair.
  • logout clears the access and refresh tokens only after server-side revocation succeeds.

See Authentication and session ownership before using a shared server client.

Registration and password login

Method and signatureReturnsBehavior
board.auth.register(body: RegisterBody, options?: FetchOptions)Promise<BoardAuthSession>Creates a candidate or employer using the emailpass method and persists the returned session.
board.auth.login(body: LoginBody, options?: FetchOptions)Promise<BoardAuthSession>Authenticates an email/password pair and persists the returned session.

RegisterBody requires role, method: 'emailpass', email, password, and displayName. Passwords must contain at least eight characters.

ts
const session = await board.auth.register({
role: 'candidate',
method: 'emailpass',
email: 'ada@example.com',
password: 'correct-horse-battery-staple',
displayName: 'Ada Lovelace',
});
console.log(session.boardUser.email);
console.log(new Date(session.expiresAt));

The SDK returns the session; it does not redirect to an account page or decide whether an unverified user can proceed.

Refresh and logout

Method and signatureReturnsBehavior
board.auth.refresh(body?: RefreshBody, options?: FetchOptions)Promise<BoardAuthSession>Rotates the refresh token, persists the replacement pair, and returns it.
board.auth.logout(body?: LogoutBody, options?: FetchOptions)Promise<void>Revokes the refresh token and clears the configured access/refresh storage after the 204 response.

When body is omitted, both methods read the refresh token from SDK storage. A nostore caller must pass it explicitly:

ts
const rotated = await board.auth.refresh({
refreshToken: session.refreshToken,
});
await board.auth.logout({
refreshToken: rotated.refreshToken,
});

If neither the body nor storage supplies a refresh token, the SDK throws a plain Error before sending a request. It is not a BoardApiError because no API response exists.

Refresh tokens are single-use. Coordinate concurrent refreshes with one shared in-flight promise or createSessionRefresher from @cavuno/board/server. Do not retry a refresh that returned 401.

Logout is idempotent on the server, including for an unknown refresh token. If the request fails because of a network or server error, the SDK deliberately retains local storage—the token might still be live server-side. Your application can retry revocation or explicitly choose a local-only sign-out.

Email verification

Method and signatureReturnsAuthentication
board.auth.verifyEmail(body: VerifyEmailBody, options?: FetchOptions)Promise<void>The email-link token authorizes the request.
board.auth.verifyEmailWithCode(body: { code: string }, options?: FetchOptions)Promise<void>Requires the signed-in user’s bearer token.
board.auth.resendVerification(options?: FetchOptions)Promise<void>Requires the signed-in user’s bearer token.

verifyEmail consumes the token included in the email link. verifyEmailWithCode consumes the six-digit code sent to the current user. Both resolve after a 204 response.

ts
await board.auth.verifyEmail({ token: tokenFromEmailLink });
await board.auth.verifyEmailWithCode(
{ code: '123456' },
{ headers: { authorization: `Bearer ${accessToken}` } },
);

resendVerification sends a fresh code and link. It resolves as a no-op when the current user is already verified.

Password reset

Method and signatureReturnsBehavior
board.auth.forgotPassword(body: ForgotPasswordBody, options?: FetchOptions)Promise<void>Accepts an email and always resolves 204 when the request is accepted, whether or not the account exists.
board.auth.resetPassword(body: ResetPasswordBody, options?: FetchOptions)Promise<void>Consumes a single-use reset token, sets a password of at least eight characters, and invalidates existing sessions.

The uniform forgot-password response prevents the endpoint from becoming an account-existence oracle.

ts
await board.auth.forgotPassword({ email: 'ada@example.com' });
await board.auth.resetPassword({
token: resetTokenFromEmail,
password: 'a-new-strong-password',
});

After a successful reset, send the user through login again. Do not assume a previously stored access token remains valid.

Method and signatureReturnsBehavior
board.auth.requestMagicLink(body: RequestMagicLinkBody, options?: FetchOptions)Promise<void>Sends a passwordless sign-in link and resolves 204.
board.auth.consumeMagicLink(body: ConsumeMagicLinkBody, options?: FetchOptions)Promise<BoardAuthSession>Exchanges the email token once and persists the returned session.

RequestMagicLinkBody accepts an email plus an optional same-origin returnTo path.

ts
await board.auth.requestMagicLink({
email: 'ada@example.com',
returnTo: '/account',
});
const session = await board.auth.consumeMagicLink({
token: tokenFromEmailLink,
});

The SDK does not navigate to returnTo; the host application owns the callback route and the post-exchange redirect.

OAuth

Method and signatureReturnsBehavior
board.auth.getOAuthAuthorizationUrl(provider: OAuthProvider, query?: OAuthAuthorizationQuery, options?: FetchOptions)Promise<OAuthAuthorizationUrl>Returns an authorization URL for 'google' or 'linkedin'.
board.auth.exchangeOAuth(body: OAuthExchangeBody, options?: FetchOptions)Promise<BoardAuthSession>Exchanges the callback’s one-time token and persists the session.
ts
const { authorizeUrl } = await board.auth.getOAuthAuthorizationUrl('google', {
returnTo: '/account',
});
window.location.assign(authorizeUrl);
// In the application’s callback route:
const session = await board.auth.exchangeOAuth({
token: callbackToken,
});

The URL method does not change browser location. Validate the callback route’s own redirect input instead of navigating to an arbitrary query parameter.

Fetch options and errors

Every method accepts FetchOptions in its final position. Standard fields such as signal and headers, plus framework fetch extensions, pass through to fetch.

Every non-2xx API response throws BoardApiError. Relevant codes include board_auth_email_taken, board_auth_invalid_credentials, board_auth_invalid_token, board_auth_registration_disabled, and board_auth_token_expired. Codes are additive within v1, so preserve a default error branch.

Use isUnauthorized for an expired or invalid session, but do not confuse it with isBoardPasswordRequired, which represents the separate board-password wall. Log error.requestId when present and never log either token.

Verify an auth implementation

  • Confirm the selected storage receives both tokens after login and receives the rotated pair after refresh.
  • Confirm two simultaneous expired-session requests produce one refresh attempt within the process.
  • Confirm invalid and reused email, magic-link, reset, and OAuth tokens fail without being retried.
  • Confirm logout clears local tokens only after revocation succeeds.
  • On SSR, confirm access and refresh tokens never appear in HTML, serialized props, URLs, public caches, or browser JavaScript.