Authentication
The Typograph API uses OAuth 2.0 for authentication. Choose the appropriate flow based on your use case.
Quick Start
For server-to-server integrations, use Client Credentials:
curl -X POST https://api.typograph.nl/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=file document publisher converter"
Response:
{
"access_token": "typ_abc123...",
"token_type": "Bearer",
"expires_in": 172800,
"scope": "file document publisher converter"
}
Getting Credentials
OAuth Client Registration
- Log in to the Typograph Portal.
- Open your organization — Settings → Organizations → your organization.
- Go to the Apps tab and click + Create App.
- Fill in the form:
- Name — a human-readable name for the app.
- Redirect URIs — add one or more callback URLs if you're building a user-facing app that will use the Authorization Code flow. Leave empty for a backend-only app using Client Credentials.
- Scopes — tick the scopes your app needs (see the Scopes reference). The available scopes depend on your organization's subscription.
- Save. The portal displays your Client ID and Client Secret once — copy both immediately.
The Client Secret is shown only once at creation. Store it in a secret manager or environment variable; the portal can't show it again.
- App with no redirect URIs →
client_credentialsgrant (server-to-server). - App with one or more redirect URIs →
authorization_code+refresh_tokengrants (user-facing).
OAuth 2.0 Flows
Client Credentials Flow
Best for server-to-server integrations where no user interaction is needed.
curl -X POST https://api.typograph.nl/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=publisher converter document"
Authorization Code Flow with PKCE
Best for web applications and mobile apps where users authenticate.
Step 1: Generate PKCE Parameters
// Generate code_verifier (43-128 characters)
const codeVerifier = generateRandomString(64);
// Generate code_challenge
const encoder = new TextEncoder();
const data = encoder.encode(codeVerifier);
const digest = await crypto.subtle.digest('SHA-256', data);
const codeChallenge = btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
Step 2: Redirect to Authorization
https://api.typograph.nl/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://your-app.com/callback
&scope=openid profile email file
&state=random_state_string
&code_challenge=CODE_CHALLENGE
&code_challenge_method=S256
Step 3: Exchange Code for Tokens
curl -X POST https://api.typograph.nl/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://your-app.com/callback" \
-d "code_verifier=CODE_VERIFIER"
Response:
{
"access_token": "typ_abc123...",
"token_type": "Bearer",
"expires_in": 172800,
"refresh_token": "typ_refresh_xyz789...",
"scope": "openid profile email file"
}
Refresh Token Flow
Exchange a refresh token for a new access token:
curl -X POST https://api.typograph.nl/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "refresh_token=YOUR_REFRESH_TOKEN"
Request the offline_access scope to receive refresh tokens.
Using Access Tokens
Include the access token in the Authorization header:
curl https://api.typograph.nl/v1/publisher/jobs \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Token Types
The Typograph API distinguishes between user tokens (issued via authorization_code / refresh_token) and client tokens (issued via client_credentials). Each gateway route requires one or the other, or accepts either.
See Token Types for the full breakdown of which endpoints require which token type and how to verify a token's type via introspection.
Token Management
Token Lifetimes
| Token Type | Lifetime |
|---|---|
| Access Token | 2 days (172,800 seconds) |
| Refresh Token | 3 days (259,200 seconds) |
| Authorization Code | 10 minutes |
Token Introspection
Verify token validity and get metadata:
curl -X POST https://api.typograph.nl/oauth/introspect \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=YOUR_ACCESS_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
Response:
{
"active": true,
"client_id": "019b28fb-a11e-7641-a28f-e978f892ec06",
"token_type": "Bearer",
"grant_type": "authorization_code",
"auth_type": "user",
"scope": "file document publisher",
"exp": 1734567890,
"iat": 1734395090,
"sub": "019b28fb-a11e-7641-a28f-e978f892ec07"
}
| Field | Description |
|---|---|
grant_type | How the token was obtained: authorization_code, client_credentials, or refresh_token |
auth_type | Token type: user (has user context) or client (no user context) |
sub | User ID (only present for user tokens) |
Token Revocation
Invalidate a token when no longer needed:
curl -X POST https://api.typograph.nl/oauth/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=YOUR_ACCESS_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
Single Sign-On (SSO)
Typograph's own login screen supports SSO via Google and Microsoft Azure AD. From your application's perspective, SSO is invisible — you use the standard Authorization Code + PKCE flow exactly as described above. When the user hits the Typograph login screen they see the "Sign in with Google" / "Sign in with Microsoft" buttons in addition to the email/password form, pick whichever they prefer, and are redirected back to your redirect_uri with an authorization code as normal.
You don't need to build anything SSO-specific into your app, and you should not redirect users directly to the /oauth/sso/* endpoints — those are used internally by Typograph's Auth UI during the login flow.
User Information
Get the authenticated user's profile (requires openid scope):
curl https://api.typograph.nl/oauth/userinfo \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response:
{
"sub": "019b28fb-a11e-7641-a28f-e978f892ec07",
"name": "John Doe",
"email": "john@example.com",
"email_verified": true
}
OAuth Discovery
Typograph implements OAuth 2.0 Authorization Server Metadata (RFC 8414):
curl https://api.typograph.nl/.well-known/oauth-authorization-server
Response:
{
"issuer": "https://api.typograph.nl",
"authorization_endpoint": "https://api.typograph.nl/oauth/authorize",
"token_endpoint": "https://api.typograph.nl/oauth/token",
"revocation_endpoint": "https://api.typograph.nl/oauth/revoke",
"introspection_endpoint": "https://api.typograph.nl/oauth/introspect",
"scopes_supported": [
"openid", "profile", "email", "offline_access",
"authorization", "health",
"identity", "identity:read", "identity:write",
"file", "file:read", "file:write", "file:delete",
"document", "document:read", "document:write",
"publisher", "publisher:read", "publisher:write",
"converter", "converter:read", "converter:write",
"webhook", "webhook:read", "webhook:write", "webhook:delete",
"subscription", "subscription:read", "subscription:write"
],
"response_types_supported": ["code"],
"response_modes_supported": ["query"],
"grant_types_supported": ["authorization_code", "client_credentials", "refresh_token"],
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
"code_challenge_methods_supported": ["S256", "plain"],
"service_documentation": "https://docs.typograph.nl"
}
The full scope catalog — including descriptions and the parent/child hierarchy — is documented in Scopes.
Client Types
Confidential Clients
Server-side applications that can securely store credentials.
- Use Client Credentials or Authorization Code flow
- Must include
client_secretin token requests - Suitable for: Backend services, server-side web apps
Public Clients
Client-side applications that cannot securely store credentials.
- Must use Authorization Code flow with PKCE
- Cannot use
client_secret - Suitable for: SPAs, mobile apps, desktop applications
Error Handling
OAuth Errors
| Error | Description |
|---|---|
invalid_request | Missing or invalid parameter |
invalid_client | Client authentication failed |
invalid_grant | Invalid authorization code or refresh token |
unauthorized_client | Client not authorized for this grant type |
unsupported_grant_type | Grant type not supported |
invalid_scope | Requested scope is invalid or exceeds granted scopes |
Error Response:
{
"error": "invalid_grant",
"error_description": "The authorization code has expired"
}
HTTP Status Codes
| Code | Description |
|---|---|
401 Unauthorized | Missing or invalid access token |
403 Forbidden | Token lacks required scope or wrong token type |
Token Type Errors
| Error Code | Description |
|---|---|
invalid_token_type | Wrong token type for endpoint (e.g., using client token on user-only endpoint) |
insufficient_scope | Token lacks required OAuth scope |
Security Best Practices
- Store credentials securely - Never commit secrets to version control
- Use environment variables - Keep credentials out of your codebase
- Request minimal scopes - Only request what your application needs
- Use PKCE - Always use PKCE for Authorization Code flow
- Rotate credentials - Periodically rotate client secrets
- Validate tokens - Use introspection for sensitive operations
- Handle expiration - Implement automatic token refresh
- Use HTTPS - Always use secure connections