Gatekeeper has two distinct credential planes: short-lived bearer access tokens for user sessions, and long-lived API keys for machine-to-machine traffic. This page covers both, plus the MFA challenge flow and OAuth.
Bearer access tokens#
login and signup return a token bundle: an accessToken, a refreshToken, an expiresIn, and the user. Apply the access token to the core with setToken / set_token, and every authenticated call thereafter sends Authorization: Bearer <token>.
import { GatekeeperCore, AuthService } from '@orkait/sdk';
const core = new GatekeeperCore({ baseUrl: 'http://localhost:8787' });
const auth = new AuthService(core);
const { accessToken, refreshToken } = await auth.login({
email: 'founder@example.com',
password: 'hunter2pass',
});
core.setToken(accessToken);
const me = await auth.me(); // now authenticatedRefresh and rotation#
Access tokens are short-lived. When one expires, exchange the refreshToken for a fresh bundle with refresh. The server rotates the refresh token, so always replace your stored refresh token with the new one from the response. Call logout to invalidate a refresh token.
- Keep the
refreshTokenfrom login somewhere durable. - When the access token expires, call
refresh(refreshToken)for a new bundle. - Re-apply the new access token and persist the new refresh token (rotation).
- On sign-out, call
logout(refreshToken).
// Rotate: exchange the old refresh token for a fresh bundle.
const next = await auth.refresh(refreshToken);
core.setToken(next.accessToken);
const newRefreshToken = next.refreshToken; // persist this, the old one is rotated out
// Sign out: invalidate the refresh token.
await auth.logout(newRefreshToken);
core.setToken(undefined);API keys#
API keys are the machine-to-machine credential, scoped to a tenant. Create a key with KeysService, then either validate the raw key, or exchange it for a short-lived RS256-signed JWT for downstream services that prefer to verify a signature.
Validate a key#
validate returns the key's metadata (tenant, scopes, status, quota) if the key is good, or throws / raises GatekeeperError if it is not.
import { KeysService } from '@orkait/sdk';
const keys = new KeysService(core);
const validated = await keys.validate('gk_live_...'); // raw key
console.log(validated.tenantId, validated.scopes);Exchange a key for an RS256 token#
token swaps a raw API key for a signed JWT (token plus tokenType). Downstream services can verify it against the published JWKS instead of calling back to validate on every request.
const exchanged = await keys.token('gk_live_...');
console.log(exchanged.token, exchanged.tokenType);MFA challenge flow#
When a user has MFA enabled, login returns a challenge (mfaRequired: true plus a challengeToken) rather than tokens. Detect it with isMfaChallenge / is_mfa_challenge, prompt the user for their TOTP code, then complete the challenge with MfaService.verifyChallenge / verify_challenge, which returns the real token bundle.
- Call
login. The result is either tokens or a challenge. - Branch with
isMfaChallenge/is_mfa_challenge. - If it is a challenge, collect the 6-digit TOTP code from the user.
- Call
verifyChallenge(challengeToken, code)to get the token bundle. - Apply the access token to the core.
import { AuthService, MfaService, isMfaChallenge } from '@orkait/sdk';
const auth = new AuthService(core);
const result = await auth.login({ email: 'founder@example.com', password: 'hunter2pass' });
if (isMfaChallenge(result)) {
const mfa = new MfaService(core);
const code = await promptUserForTotp(); // your UI
const tokens = await mfa.verifyChallenge(result.challengeToken, code);
core.setToken(tokens.accessToken);
} else {
core.setToken(result.accessToken);
}OAuth#
For social or SSO login, OAuthService produces an authorization URL and consumes the provider callback. Send the user to the returned url, keep the state, and when the provider redirects back, hand the callback parameters to callback to receive the token bundle.
- Call
authorize(provider)to get a redirecturland astate. - Redirect the user to
url; persiststateto compare on return. - On the provider redirect back, call
callbackwithstateand thecode(or theerrorthe provider returned). - Apply the returned access token to the core.
import { OAuthService } from '@orkait/sdk';
const oauth = new OAuthService(core);
// 1. Begin the flow.
const { url, state } = await oauth.authorize('google');
// ...redirect the user to `url`, stash `state`...
// 3. Complete it when the provider redirects back with ?code=...&state=...
const tokens = await oauth.callback('google', { state, code: 'returned-code' });
core.setToken(tokens.accessToken);Credential cheat sheet#
| Credential | Lifetime | How you get it | How you apply it |
|---|---|---|---|
| Access token | Short | login / signup / refresh / verifyChallenge / OAuth callback | setToken / set_token |
| Refresh token | Long, rotated | Same token bundle | Passed to refresh / logout |
| API key | Long | keys.create (plaintext shown once) | validate or token exchange |
| RS256 JWT | Short | keys.token | Verified downstream against JWKS |