OAuth2 Authentication
Snapbooks API uses OAuth2 for secure authentication and authorization. This provides a robust framework for secure API access while allowing fine-grained control over permissions.
Overview
OAuth2 is an industry-standard protocol that allows secure API authorization in a simple and standard way. Snapbooks supports three OAuth2 grant types:
- Authorization Code Grant - For applications that can securely store client secrets (web applications)
- Authorization Code with PKCE - For public clients that cannot securely store secrets (mobile/single-page apps)
- Client Credentials Grant - For server-to-server API access
OAuth2 Endpoints
Endpoint | Description |
---|---|
POST /snapbooks/api/v2/oauth/clients |
Register a new OAuth client application |
GET /snapbooks/api/v2/oauth/clients |
List registered OAuth clients |
DELETE /snapbooks/api/v2/oauth/clients/{client_id} |
Delete an OAuth client |
GET /snapbooks/public/v2/oauth/authorize |
Authorization endpoint to obtain user consent |
POST /snapbooks/public/v2/oauth/token |
Token endpoint to obtain access and refresh tokens |
POST /snapbooks/public/v2/oauth/revoke |
Revocation endpoint to invalidate tokens |
Client Registration
Before using OAuth2, you must register a client application:
Register a new client
POST /snapbooks/api/v2/oauth/clients
Authorization: Bearer {your-admin-token}
Content-Type: application/json
{
"client_name": "My Accounting App",
"redirect_uris": "https://myapp.example.com/callback",
"grant_types": "authorization_code refresh_token",
"scope": "read:accounts write:transactions"
}
Response:
{
"client_id": "AbCdEfGhIjKlMnOpQrStUv",
"client_secret": "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz",
"client_name": "My Accounting App",
"redirect_uris": "https://myapp.example.com/callback",
"grant_types": "authorization_code refresh_token",
"scope": "read:accounts write:transactions"
}
Important: Store the client_id
and client_secret
securely - the secret will not be retrievable later.
List registered clients
GET /snapbooks/api/v2/oauth/clients
Authorization: Bearer {your-admin-token}
Response:
{
"clients": [
{
"client_id": "AbCdEfGhIjKlMnOpQrStUv",
"client_name": "My Accounting App",
"redirect_uris": "https://myapp.example.com/callback",
"grant_types": "authorization_code refresh_token",
"scope": "read:accounts write:transactions",
"created_at": "2025-04-10T14:27:35.123456"
}
]
}
Delete a client
DELETE /snapbooks/api/v2/oauth/clients/{client_id}
Authorization: Bearer {your-admin-token}
Response:
{
"status": "success",
"message": "Client deleted"
}
Authorization Code Flow
This flow is suitable for web applications that can securely store client secrets.
1. Request Authorization Code
GET /snapbooks/public/v2/oauth/authorize?
response_type=code&
client_id={client_id}&
redirect_uri=https%3A%2F%2Fmyapp.example.com%2Fcallback&
scope=read%3Aaccounts%20write%3Atransactions&
state={random_state_value}
Parameters:
response_type
: Must becode
client_id
: Your application’s client IDredirect_uri
: URL-encoded callback URL (must match a pre-registered value)scope
: Space-separated list of requested permissionsstate
: Random string to prevent CSRF attacks
The user will be prompted to log in (if not already) and authorize your application’s access.
2. Exchange Code for Tokens
After the user authorizes access, they’re redirected to your application:
https://myapp.example.com/callback?code={authorization_code}&state={random_state_value}
Verify that the state
matches the one you generated, then exchange the code for tokens:
POST /snapbooks/public/v2/oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {base64(client_id:client_secret)}
grant_type=authorization_code&
code={authorization_code}&
redirect_uri=https%3A%2F%2Fmyapp.example.com%2Fcallback
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def50200fe37bb71b1baba9b5f2d5...",
"scope": "read:accounts write:transactions"
}
Authorization Code with PKCE
For public clients (like mobile/SPA apps) that can’t securely store secrets, use PKCE (Proof Key for Code Exchange):
1. Generate a Code Verifier and Challenge
// Generate a random code verifier
const codeVerifier = generateRandomString(64);
// Create the code challenge using S256 method
const codeChallenge = base64UrlEncode(sha256(codeVerifier));
2. Request Authorization Code with PKCE
GET /snapbooks/public/v2/oauth/authorize?
response_type=code&
client_id={client_id}&
redirect_uri=https%3A%2F%2Fmyapp.example.com%2Fcallback&
scope=read%3Aaccounts%20write%3Atransactions&
state={random_state_value}&
code_challenge={code_challenge}&
code_challenge_method=S256
3. Exchange Code for Tokens with PKCE
POST /snapbooks/public/v2/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
client_id={client_id}&
code={authorization_code}&
redirect_uri=https%3A%2F%2Fmyapp.example.com%2Fcallback&
code_verifier={code_verifier}
Client Credentials Flow
For server-to-server authentication without user involvement:
POST /snapbooks/public/v2/oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {base64(client_id:client_secret)}
grant_type=client_credentials&
scope=read%3Aaccounts%20write%3Atransactions
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read:accounts write:transactions"
}
Using Refresh Tokens
Access tokens expire after 1 hour. Use a refresh token to get a new access token:
POST /snapbooks/public/v2/oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {base64(client_id:client_secret)}
grant_type=refresh_token&
refresh_token={refresh_token}
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def50200ca01d5cf123b6ba9c5f2a...", // New refresh token
"scope": "read:accounts write:transactions"
}
Note: Snapbooks uses token rotation for security. Each time you use a refresh token, you’ll receive a new one, and the old one becomes invalid.
Revoking Tokens
When a user logs out or you no longer need access:
POST /snapbooks/public/v2/oauth/revoke
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {base64(client_id:client_secret)}
token={refresh_token}&
token_type_hint=refresh_token
Making Authenticated Requests
Use the access token for all API requests:
GET /snapbooks/api/v2/banking/accounts
Authorization: Bearer {access_token}
Error Responses
OAuth2 endpoints return standard error responses:
Error | Description |
---|---|
invalid_request |
The request is missing a required parameter |
invalid_client |
Client authentication failed |
invalid_grant |
The provided authorization code or refresh token is invalid |
unauthorized_client |
The client is not authorized to use the requested grant type |
unsupported_grant_type |
The requested grant type is not supported |
invalid_scope |
The requested scope is invalid or unknown |
access_denied |
The user denied the authorization request |
Example error response:
{
"error": "invalid_grant",
"error_description": "Refresh token expired"
}
Security Best Practices
- Store tokens securely:
- Never store tokens in localStorage in browser apps
- Use secure HTTP-only cookies or secure storage mechanisms
- For mobile apps, use the platform’s secure storage (Keychain/Keystore)
-
Implement proper PKCE for public clients (mobile/SPA apps)
-
Always validate state parameters to prevent CSRF attacks
-
Request minimal scopes - only ask for the permissions your app needs
- Implement token management:
- Handle token expiration gracefully
- Revoke tokens when a user logs out
- Implement proper error handling for authentication failures
- Norwegian regulatory compliance:
- Ensure GDPR compliance with proper user consent
- Follow Datatilsynet guidelines for storing personal data
- Implement appropriate logging for audit purposes according to Norwegian bookkeeping regulations