Authentication

To call the Manabu2 API you use either an OAuth 2.0 access token, which acts on behalf of a user, or an API key, which acts as your organization. Manabu2 runs its own authorization server; there's no integration with external identity providers such as Microsoft Entra ID today.


1. Which one to use

Access token (OAuth) API key
Acts asThe user who signed inThe organization itself (not tied to a person)
What it can doScopes allowed for the app ∩ scopes requested ∩ the user's own permissionsExactly the scopes set on the key
Best forMobile apps, internal portal screens, MCP-capable AI assistantsNightly batch jobs, HR-system sync, BI feeds
ExpiryAccess token lasts expires_in seconds (currently 24 hours); renew it with the refresh tokenValid until revoked (you can also set an expiry date)

Register apps and issue API keys from the developer menu in Manabu2. You need developer or organization-admin rights.

2. Signing users in with their Manabu2 account (authorization code + PKCE)

Users type their password on a Manabu2 screen, so your app never receives it. PKCE (S256) is required.

① Create a PKCE pair and a state value
code_verifier  = base64url(32–64 random bytes)
code_challenge = base64url(sha256(code_verifier))
state          = base64url(16 random bytes)
② Send the user to the sign-in screen
GET https://manabu2.com/connect/authorize
  ?client_id={client_id}
  &redirect_uri={registered redirect URI}
  &response_type=code
  &scope=read%3Acatalog%20read%3Acontent%20read%3Aprogress%20write%3Aprogress
  &state={state}
  &code_challenge={code_challenge}
  &code_challenge_method=S256

redirect_uri must exactly match one you registered. On mobile, open this in the system browser (ASWebAuthenticationSession / Chrome Custom Tabs), not an in-app WebView. When the user comes back, always check that state matches the value you sent.

③ Exchange the authorization code for tokens
POST https://api.manabu2.com/api/v1/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code={code}
&client_id={client_id}
&redirect_uri={same redirect URI}
&code_verifier={code_verifier}

A JSON body works too. Confidential clients also send client_secret. A code expires after 60 seconds and works only once. The response contains access_token, token_type, expires_in, refresh_token and scope.

④ Call the API
GET https://api.manabu2.com/api/v1/courses
Authorization: Bearer {access_token}

3. Refreshing tokens

POST https://api.manabu2.com/api/v1/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token={refresh_token}
  • Every refresh returns a new refresh token and invalidates the old one. Always save the new value.
  • Presenting an old refresh token again is refused (the session itself stays active). Don't run refresh from several threads at once.
  • The access token's lifetime comes back in expires_in; use that value rather than hard-coding one. Refresh tokens last 30 days.

4. API keys

An API key is a credential for server-to-server integrations with no user involved. Send it in either form:

X-Api-Key: mnb_live_...
Authorization: Bearer mnb_live_...
  • The key is shown only once, right after you issue it. Only a hash is stored, so it can't be retrieved later.
  • A key holds its scopes outright; no user's permissions narrow them. Only organization admins can issue keys that include admin scopes.
  • Never embed an API key in a mobile app or in JavaScript that runs in the browser. Anything that runs on a user's device should use OAuth.

5. Password sign-in (POST /api/v1/auth/login)

The endpoint that exchanges an email and password for tokens is for Manabu2's own apps. It refuses third-party client_ids. In your own apps, use the authorization code + PKCE flow above.

6. Common errors

  • redirect_uri mismatch — a trailing slash, http vs https or a different port is enough to be rejected. Send the same string in ② and ③.
  • Missing code_challenge, or a method other than S256 — PKCE with S256 is required.
  • invalid_grant — the code expired (60 seconds), was already used, or the code_verifier doesn't match. Start again from ①.
  • 401 — the token or key is missing, expired or revoked, or the account has been deactivated.
  • 403 — you're authenticated, but the credential lacks the required scope or has no access to that organization or data.
  • 429 — you've hit the rate limit. Wait the number of seconds in the Retry-After header, then retry.

Next: REST API docs →