Authentication
The client sends one kind of credential per request. Pick it by where your code runs.
createClient({ baseUrl, token: 'lh_…' })- An org API token, from Dashboard → Developers → API Access.
- Acts on that org with the token’s permissions.
- Next.js route handlers, workers, scripts, CI.
createClient({ baseUrl, getToken })- The signed-in learner’s access token, or their cookie session.
- Sees exactly what that learner can see.
- Never ship an
lh_token to a browser.
Org API token (servers)
const lh = createClient({
baseUrl: process.env.LEARNHOUSE_URL!,
token: process.env.LEARNHOUSE_TOKEN!, // lh_…
})Create the token in the dashboard under Developers → API Access. It acts on one organization, with the permissions you give it (read-only, full, or per resource), and never more than the user who created it. See API tokens for permissions, expiry and what tokens can't do.
An API token is a password for your organization's content. Keep it in server environment variables. Never put it in browser code, a mobile app, or a repository.
Signed-in learner (browsers and apps)
Requests made as a learner see exactly what that learner can see, and progress (trail) is recorded for them.
Browser on the instance's domain: the cookie
const lh = createClient({ baseUrl: 'https://learn.your-school.com', credentials: 'include' })
const me = await lh.users.session()The learner's LearnHouse session cookie is sent along. This works when your page runs on the instance's domain (or a subdomain it trusts), since the API only answers browsers on origins it allows.
Your own token storage: getToken
getToken is called before every request, so the client always uses your freshest token:
const lh = createClient({
baseUrl: 'https://learn.your-school.com',
getToken: () => tokenStore.accessToken, // string, null, or a Promise of either
})Signing in with email and password
const res = await lh.auth.login({ email, password })
if (res.mfa_required) {
// Ask for the 6-digit code, then:
const session = await lh.auth.loginMfa({ mfaToken: res.mfa_token, code })
}
// res.tokens.access_token → valid for 8 hours
// res.tokens.refresh_token → single-use: store the new one after every refreshRefreshing
const tokens = await lh.auth.refresh({ refreshToken: stored.refreshToken })
// Store both tokens.access_token and tokens.refresh_token.In a browser on the instance's domain, lh.auth.refresh() without arguments uses the refresh cookie.
Refresh is never retried automatically: a refresh token can be used once, and replaying it signs the learner out everywhere. If a refresh fails on a network error, ask the learner to sign in again.
Signing out
await lh.auth.logout()Per-request options
Skip auth for one call, or add headers:
await lh.orgs.get('your-school', { skipAuth: true })
await lh.courses.get('course_…', { headers: { 'X-Request-Id': id } })