Authentication
The Monogoto API uses JWT Bearer tokens for authentication. This guide covers how to obtain tokens, use them correctly, keep them fresh, and handle the edge cases that trip up most integrations.
How It Works
Authentication follows the standard OAuth 2.0 password grant pattern:
- Login — send credentials to
/v1/auth/token, receive an access token and a refresh token - Authorise — include the access token in the
Authorization: Bearerheader on every API request - Refresh — when the access token nears expiry, exchange the refresh token for a new pair at
/v1/auth/refresh - Re-login — if the refresh token has expired (after 24 hours of inactivity), repeat step 1
POST /v1/auth/token
↓ access_token (4h) + refresh_token (24h)
Every API request
→ Authorization: Bearer <access_token>
Before access_token expires
POST /v1/auth/refresh
→ new access_token + new refresh_token (old one invalidated)
Obtaining a Token
Request
POST /v1/auth/token
Content-Type: application/json
{
"username": "your@email.com",
"password": "your-password"
}
curl -X POST https://api.monogoto.io/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"username": "your@email.com", "password": "your-password"}'
Response
{
"token_type": "Bearer",
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
| Field | Type | Description |
|---|---|---|
token_type |
string | Always "Bearer". Prefix this value to the token in the header. |
access_token |
string | Short-lived JWT. Use this on every API call. Valid for 4 hours. |
refresh_token |
string | Long-lived JWT. Use this to refresh the access token. Valid for 24 hours, single-use. |
Using the Access Token
Include the token in every API request as an Authorization header:
GET /v1/things
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
If the header is missing or the token is invalid, the API returns 401 Unauthorized. If the token lacks the required scope for the endpoint, it returns 403 Forbidden.
Refreshing Tokens
Access tokens expire after 4 hours. Use the refresh flow to extend the session without prompting the user for credentials again.
Request
POST /v1/auth/refresh
Content-Type: application/json
{
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response
The response shape is identical to the login response — you receive a new access_token and a new refresh_token.
Important: The previous
refresh_tokenis invalidated the moment a new one is issued. Always replace both tokens in storage after a refresh.
Refresh Token Expiry
Refresh tokens are valid for 24 hours from the time of issue. If a refresh attempt returns 401, the refresh token has expired or been invalidated. Fall back to a full login.
async function ensureFreshToken(tokenStore) {
const BUFFER_MS = 5 * 60 * 1000; // refresh 5 min before expiry
if (Date.now() < tokenStore.accessTokenExpiresAt - BUFFER_MS) {
return; // still valid
}
try {
const res = await fetch('https://api.monogoto.io/v1/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: tokenStore.refreshToken }),
});
if (res.status === 401) {
// Refresh token expired — full re-login required
return login(tokenStore);
}
const data = await res.json();
tokenStore.accessToken = data.access_token;
tokenStore.refreshToken = data.refresh_token;
tokenStore.accessTokenExpiresAt = Date.now() + 4 * 60 * 60 * 1000;
} catch (err) {
console.error('Token refresh failed:', err);
throw err;
}
}
Token Lifecycle at a Glance
| Token | Valid for | Single-use | What happens on expiry |
|---|---|---|---|
access_token |
4 hours | No | API returns 401 — refresh it |
refresh_token |
24 hours | Yes | Refresh returns 401 — re-login |
API Scopes
Tokens carry scopes that gate access to certain endpoints. The required scope for each endpoint is shown as a badge in the API Reference. Common scopes include:
| Scope | Access granted |
|---|---|
read |
Read-only access to resources (GET endpoints) |
write |
Create and modify resources (POST, PUT, PATCH) |
admin |
Admin-only endpoints and bulk operations |
If your token lacks the required scope, the API returns 403 Forbidden. Contact support@monogoto.io to adjust scope assignments for your account.
Token Storage Recommendations
| Environment | Recommended storage |
|---|---|
| Server-side (Node.js, Python, etc.) | In-memory, or encrypted at rest in a secrets manager (e.g. AWS Secrets Manager, HashiCorp Vault) |
| CI/CD pipelines | Environment variables injected at runtime — never in the repository |
| Browser-based apps | sessionStorage for short sessions; never localStorage for production secrets |
| Mobile apps | iOS Keychain / Android Keystore |
Security Best Practices
Never expose tokens in client-side code or URLs.
Tokens in JavaScript bundles, query strings, or browser history can be extracted trivially. Always pass them via headers from a server-side context.
Use environment variables.
Store credentials in env vars (e.g. MONOGOTO_USER, MONOGOTO_PASS) and inject tokens at runtime. Never hard-code them.
Rotate on breach.
If a token is exposed — in logs, error reports, or a public commit — contact support@monogoto.io immediately to invalidate it. Then rotate your credentials.
Prefer refresh over re-login.
Repeated login calls against /v1/auth/token are rate-limited to 5 per 60 seconds per IP. Use the refresh flow to stay within limits in long-running services.
Log request IDs, not tokens.
When logging API errors for debugging, record the request_id from the error response. This is safe to share with support and provides full traceability.
Related Guides
- Rate Limits — Auth endpoints have their own IP-based rate limit; understand it before building auto-retry logic
- Error Reference —
401and403explained in full with fix guidance - Quickstart — End-to-end working example with automatic token refresh