Edit

Authentication

The client sends one kind of credential per request. Pick it by where your code runs.

On your server
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.
In a browser or app
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.

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.

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 refresh

Refreshing

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 } })