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 as | The user who signed in | The organization itself (not tied to a person) |
| What it can do | Scopes allowed for the app ∩ scopes requested ∩ the user's own permissions | Exactly the scopes set on the key |
| Best for | Mobile apps, internal portal screens, MCP-capable AI assistants | Nightly batch jobs, HR-system sync, BI feeds |
| Expiry | Access token lasts expires_in seconds (currently 24 hours); renew it with the refresh token | Valid 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 →