Authentication
Authentication
The Lumanu Partner API supports two authentication methods to accommodate different integration scenarios. Choose the appropriate method based on whether your integration needs to manage workspaces autonomously or act on behalf of users.
Authentication Methods Overview
Client Credentials Flow
Best for: Server-to-server integrations where your application manages workspaces it owns
Use this flow when:
- Your platform creates and manages workspaces on behalf of your business
- You need programmatic access to automate payment workflows
- Your integration operates independently without user interaction
- You're implementing the Platform-Mediated money flow (your platform is in the money flow)
OAuth Authorization Code Flow
Best for: Third-party integrations that act on behalf of users
Use this flow when:
- Users need to grant your application access to their Lumanu workspaces
- You're building an integration that users install or authorize
- You need to perform actions on behalf of specific users
- You're implementing the Direct Client flow (clients manage their own workspaces)
Client Credentials Flow
The Client Credentials flow provides secure server-to-server authentication for applications that manage their own workspaces.
Getting Access Tokens
- You will receive a Client ID and Client Secret from Lumanu
- Exchange these credentials for an access token by making a POST request to the appropriate authentication endpoint for your environment:
POST https://{environment-auth-domain}/oauth/token
Content-Type: application/json
{
"client_id": "{your_client_id}",
"client_secret": "{your_client_secret}",
"audience": "{api-base-domain}",
"grant_type": "client_credentials"
}Environment-specific values:
| Environment | Auth Domain | API Base Domain |
|---|---|---|
| Sandbox | auth-staging.lumanu.com | https://lumanu-demo.hasura.app/v1/graphql |
| Production | auth.lumanu.com | https://lumanu-prod.hasura.app/v1/graphql |
Example Response:
{
"access_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 86400
}Using Access Tokens
Include the access token in the Authorization header of all API requests:
Authorization: Bearer eyJhbGc...
Token Lifecycle
- Access tokens are valid for 24 hours (86400 seconds)
- Request a new token when the current token expires
- Store tokens securely and never expose them in client-side code
- Do not share tokens between different integrations
Example Use Case
Your payment automation platform creates workspaces for internal use and programmatically manages all payment operations:
// Get access token
const response = await fetch('https://auth-staging.lumanu.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: process.env.LUMANU_CLIENT_ID,
client_secret: process.env.LUMANU_CLIENT_SECRET,
audience: 'https://lumanu-demo.hasura.app/v1/graphql',
grant_type: 'client_credentials',
}),
});
const { access_token } = await response.json();
// Use token to create a payable
await fetch('https://api.demo.lumanu.link/api/rest/payable', {
method: 'POST',
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
workspace_id: 'your-workspace-id',
payee_email: '[email protected]',
amount: 150000,
description: 'Campaign payment',
}),
});OAuth Authorization Code Flow
The OAuth Authorization Code flow enables third-party applications to act on behalf of users with their explicit consent.
Flow Diagram
sequenceDiagram
participant User as User's Browser
participant App as Your Application
participant Lumanu as Lumanu OAuth
participant Auth0 as Auth0 Login
User->>App: 1. User clicks "Connect Lumanu"
App->>User: 2. Redirect to /api/oauth/authorize<br/>?client_id=...<br/>&redirect_uri=https://yourapp.com/callback<br/>&response_type=code<br/>&scope=openid profile email<br/>&state=random_string
User->>Lumanu: 3. GET /api/oauth/authorize
Lumanu->>Auth0: 4. Redirect to Auth0<br/>(with audience automatically added)
Auth0->>User: 5. Display login page
User->>Auth0: 6. User authenticates & authorizes
Auth0->>User: 7. Redirect to callback<br/>?code=auth_code&state=random_string
User->>App: 8. GET /oauth/callback?code=...&state=...
App->>Auth0: 9. POST /oauth/token<br/>Exchange code for access token
Auth0->>App: 10. Return access_token, refresh_token
App->>App: 11. Store tokens securely
App->>Lumanu: 12. Make API calls with access token
Lumanu->>App: 13. API responses
App->>User: 14. Display success & return to app
Implementation Steps
Step 1: Register Your OAuth Application
Contact Lumanu to register your application and receive:
- Client ID: Public identifier for your application
- Client Secret: Secret credential (keep secure, never expose client-side)
- Allowed Redirect URIs: Whitelisted callback URLs
Step 2: Initiate Authorization
Redirect users to the Lumanu OAuth authorization endpoint with the following parameters:
Authorization URL:
GET https://api.{environment}.lumanu.link/api/oauth/authorize
Required Query Parameters:
| Parameter | Description | Example |
|---|---|---|
client_id | Your OAuth client ID | abc123xyz |
redirect_uri | Your callback URL (must be pre-registered) | https://yourapp.com/oauth/callback |
response_type | Must be code for authorization code flow | code |
state | Random string for CSRF protection | random_string_123 |
Optional Parameters:
| Parameter | Description | Example |
|---|---|---|
scope | Space-separated scopes (defaults to openid profile email) | openid profile email |
audience | API audience (auto-populated if not provided) | https://lumanu-demo.hasura.app/v1/graphql |
Example Authorization URL:
https://api.demo.lumanu.link/api/oauth/authorize
?client_id=your_client_id
&redirect_uri=https://yourapp.com/oauth/callback
&response_type=code
&state=random_string_for_csrf_protection
&scope=openid profile email
Step 3: Handle the Callback
After the user authorizes your application, they'll be redirected to your redirect_uri with an authorization code:
https://yourapp.com/oauth/callback
?code=AUTHORIZATION_CODE
&state=random_string_for_csrf_protection
Important: Always verify the state parameter matches what you sent to prevent CSRF attacks.
Step 4: Exchange Code for Access Token
Exchange the authorization code for an access token by making a POST request to Auth0's token endpoint:
POST https://{environment-auth-domain}/oauth/token
Content-Type: application/json
{
"client_id": "{your_client_id}",
"client_secret": "{your_client_secret}",
"code": "{authorization_code}",
"grant_type": "authorization_code",
"redirect_uri": "{same_redirect_uri_from_step_2}"
}Environment-specific Auth Domains:
- Sandbox:
auth-staging.lumanu.com - Production:
auth.lumanu.com
Example Response:
{
"access_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 86400,
"refresh_token": "v1.abc...",
"id_token": "eyJhbGc..."
}Step 5: Make Authenticated API Requests
Use the access token to make API requests on behalf of the user:
Authorization: Bearer eyJhbGc...
Token Management
Access Tokens:
- Valid for 24 hours (86400 seconds)
- Should be stored securely (encrypted database or secure session)
- Never expose in client-side code or URLs
Refresh Tokens:
- Can be used to obtain new access tokens without user interaction
- Valid for extended periods (check token response)
- Store with same security as access tokens
Refreshing Tokens:
POST https://{environment-auth-domain}/oauth/token
Content-Type: application/json
{
"client_id": "{your_client_id}",
"client_secret": "{your_client_secret}",
"grant_type": "refresh_token",
"refresh_token": "{refresh_token}"
}Example Implementation
Node.js/Express Example:
const express = require('express');
const crypto = require('crypto');
const app = express();
// Configuration
const LUMANU_CLIENT_ID = process.env.LUMANU_CLIENT_ID;
const LUMANU_CLIENT_SECRET = process.env.LUMANU_CLIENT_SECRET;
const LUMANU_AUTH_URL = 'https://api.demo.lumanu.link/api/oauth/authorize';
const AUTH0_DOMAIN = 'auth-staging.lumanu.com';
const REDIRECT_URI = 'https://yourapp.com/oauth/callback';
// Step 1: Initiate OAuth flow
app.get('/connect/lumanu', (req, res) => {
const state = crypto.randomBytes(16).toString('hex');
// Store state in session for verification
req.session.oauthState = state;
const authUrl = new URL(LUMANU_AUTH_URL);
authUrl.searchParams.set('client_id', LUMANU_CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('state', state);
authUrl.searchParams.set('scope', 'openid profile email');
res.redirect(authUrl.toString());
});
// Step 2: Handle OAuth callback
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
// Verify state to prevent CSRF
if (state !== req.session.oauthState) {
return res.status(403).send('Invalid state parameter');
}
try {
// Exchange code for access token
const tokenResponse = await fetch(`https://${AUTH0_DOMAIN}/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: LUMANU_CLIENT_ID,
client_secret: LUMANU_CLIENT_SECRET,
code: code,
grant_type: 'authorization_code',
redirect_uri: REDIRECT_URI,
}),
});
const tokens = await tokenResponse.json();
// Store tokens securely (encrypted in database)
await storeUserTokens(req.user.id, {
access_token: tokens.access_token,
refresh_token: tokens.refresh_token,
expires_at: Date.now() + tokens.expires_in * 1000,
});
// Get user's workspaces
const workspacesResponse = await fetch(
'https://api.demo.lumanu.link/api/rest/user/current/workspaces',
{
headers: {
Authorization: `Bearer ${tokens.access_token}`,
},
}
);
const workspaces = await workspacesResponse.json();
res.redirect('/dashboard?connected=success');
} catch (error) {
console.error('OAuth error:', error);
res.status(500).send('Authentication failed');
}
});
// Step 3: Make API calls with stored token
app.post('/create-payment', async (req, res) => {
const tokens = await getUserTokens(req.user.id);
// Check if token needs refresh
if (Date.now() >= tokens.expires_at) {
tokens = await refreshAccessToken(tokens.refresh_token);
}
const response = await fetch(
'https://api.demo.lumanu.link/api/rest/payable',
{
method: 'POST',
headers: {
Authorization: `Bearer ${tokens.access_token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
workspace_id: req.body.workspace_id,
payee_email: req.body.payee_email,
amount: req.body.amount,
description: req.body.description,
}),
}
);
const payable = await response.json();
res.json(payable);
});
async function refreshAccessToken(refreshToken) {
const response = await fetch(`https://${AUTH0_DOMAIN}/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: LUMANU_CLIENT_ID,
client_secret: LUMANU_CLIENT_SECRET,
grant_type: 'refresh_token',
refresh_token: refreshToken,
}),
});
const tokens = await response.json();
// Update stored tokens
await storeUserTokens(userId, {
access_token: tokens.access_token,
refresh_token: tokens.refresh_token || refreshToken,
expires_at: Date.now() + tokens.expires_in * 1000,
});
return tokens;
}Testing OAuth Flow
Lumanu provides an OAuth test server to help you test the OAuth flow during development.
Starting the test server:
cd oauth-test-server
doppler run -- npm run devThe test server provides a simple interface to:
- Initiate the OAuth flow
- Complete authentication
- Extract and display access tokens
- Test API calls with the token
Note: The test server is only for development and testing purposes.
Security Best Practices
For Both Methods
-
Never expose credentials client-side
- Client secrets and access tokens should only be used in server-side code
- Never include them in frontend JavaScript, mobile apps, or version control
-
Use HTTPS only
- All authentication requests must use HTTPS
- Redirect URIs must use HTTPS (except localhost for testing)
-
Store tokens securely
- Encrypt tokens at rest in your database
- Use secure session management
- Never log tokens or include them in error messages
-
Implement token rotation
- Refresh access tokens before they expire
- Invalidate tokens when users disconnect your integration
OAuth-Specific
-
Validate state parameter
- Always verify the state parameter matches to prevent CSRF attacks
- Use cryptographically random values
-
Validate redirect_uri
- Ensure the redirect URI exactly matches what was registered
- Use strict string comparison
-
Handle errors gracefully
- Check for error parameters in callback (
?error=access_denied) - Provide clear error messages to users
- Check for error parameters in callback (
-
Scope management
- Request only the scopes you need
- Clearly explain to users what permissions you're requesting
Choosing the Right Method
| Scenario | Recommended Method | Reason |
|---|---|---|
| Users need to connect their existing Lumanu accounts | OAuth | Users retain control and can revoke access |
| Building a marketplace integration | OAuth | Multiple users with different permissions |
| Automated payment processing for your business | Client Credentials | No user interaction needed |
| Third-party app installed by users | OAuth | User explicitly grants access |
| Internal tools and scripts | Client Credentials | Your organization owns the integration |
API Endpoints for User Information
When using OAuth (acting on behalf of a user), you can access user-specific information:
Get Current User
GET /api/rest/user/current
Authorization: Bearer {user_access_token}Response:
{
"id": "user-uuid",
"first_name": "John",
"last_name": "Doe",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}Get User's Workspaces
GET /api/rest/user/current/workspaces
Authorization: Bearer {user_access_token}Response:
{
"data": [
{
"id": "workspace-uuid",
"display_name": "Acme Corp",
"role": {
"id": "role-uuid",
"display_name": "Admin"
}
}
]
}These endpoints are only accessible with user access tokens obtained through OAuth, not with client credentials tokens.
Need Help?
If you have questions about authentication or need help implementing OAuth:
- Check the API Reference for detailed endpoint documentation
- Review the Environments guide for environment-specific URLs
- Contact Lumanu support for OAuth application registration
- Use the oauth-test-server for development and testing
Updated 13 days ago