Partner Event API Authentication
Learn how to authenticate requests to the CHeKT Partner Event API
Partner Event API Authentication
The Partner Event API uses OAuth 2.0 Client Credentials Grant with JWT assertions for M2M (Machine-to-Machine) authentication. This guide explains how to set up authentication for sending events to CHeKT.
Different from Partner API
While both Partner API and Partner Event API use OAuth 2.0, they have different authentication requirements:
- Partner API: Requires Authorization Code Flow for Dealer Connect + M2M for other endpoints
- Partner Event API: Only requires M2M authentication (no Authorization Code Flow)
See Partner API Authentication for Partner API details.
Overview
The Partner Event API authentication is simpler than the Partner API because it only requires M2M authentication. There's no need for the Authorization Code Flow.
Authentication Method: OAuth 2.0 Client Credentials Grant with JWT Bearer Assertions
Authentication Flow
sequenceDiagram
participant Partner as Your Platform
participant Auth as CHeKT Auth Server
participant EventAPI as Event API
Partner->>Partner: Create JWT Assertion
Partner->>Partner: Sign with M2M Secret
Partner->>Auth: POST /oauth/token (with assertion)
Auth->>Auth: Verify signature
Auth->>Partner: Return access_token
Partner->>EventAPI: POST /partner/v1/events (Bearer token)
EventAPI->>Partner: Return upload URLs
Step 1: Register Auth Application
Before using the Partner Event API, you must register an Auth Application for event ingestion with CHeKT.
Registration Requirements
Contact CHeKT support to register your Auth Application. You will need to provide:
- Application Name: Your platform or company name
- Public Key: Your RSA public key for JWT signing verification
- Additional Information:
- Event types you'll send (alarm, trouble, arming)
- Expected event volume
- Platform technical details
What You Receive
After registration, you will receive:
- Client ID: Your application identifier
- Secret Key: Your private secret for signing JWT assertions
- Auth Server URL: The token endpoint for authentication
Keep Credentials Secure
- Store your secret key securely - never commit it to version control
- Treat credentials like passwords
- Use separate credentials for development and production
- Rotate keys periodically for enhanced security
Step 2: Create JWT Assertion Token
Generate a JWT assertion token signed with your M2M secret key.
JWT Claims
Your JWT must include these claims:
{
"iss": "YOUR_CLIENT_ID",
"sub": "YOUR_CLIENT_ID",
"aud": "https://auth.chekt.com",
"exp": 1234567890,
"iat": 1234567800,
"jti": "unique-jwt-id"
}
Claim Descriptions:
| Claim | Description |
|---|---|
iss | Issuer - your Client ID |
sub | Subject - your Client ID |
aud | Audience - CHeKT auth server URL |
exp | Expiration time (Unix timestamp, typically 5 minutes from iat) |
iat | Issued at time (Unix timestamp) |
jti | JWT ID - unique identifier to prevent replay attacks |
Sign with Secret Key
Sign the JWT using your M2M secret key with the RS256 algorithm:
Node.js Example:
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
// Your M2M credentials
const CLIENT_ID = process.env.CHEKT_EVENT_CLIENT_ID;
const SECRET_KEY = process.env.CHEKT_EVENT_SECRET_KEY;
function createJWTAssertion() {
const now = Math.floor(Date.now() / 1000);
const claims = {
iss: CLIENT_ID,
sub: CLIENT_ID,
aud: 'https://auth.chekt.com',
exp: now + 300, // Expires in 5 minutes
iat: now,
jti: crypto.randomUUID()
};
return jwt.sign(claims, SECRET_KEY, { algorithm: 'RS256' });
}
const assertion = createJWTAssertion();
console.log('JWT Assertion:', assertion);
Python Example:
import jwt
import time
import uuid
import os
# Your M2M credentials
CLIENT_ID = os.getenv('CHEKT_EVENT_CLIENT_ID')
SECRET_KEY = os.getenv('CHEKT_EVENT_SECRET_KEY')
def create_jwt_assertion():
now = int(time.time())
claims = {
"iss": CLIENT_ID,
"sub": CLIENT_ID,
"aud": "https://auth.chekt.com",
"exp": now + 300, # Expires in 5 minutes
"iat": now,
"jti": str(uuid.uuid4())
}
return jwt.encode(claims, SECRET_KEY, algorithm="RS256")
assertion = create_jwt_assertion()
print(f"JWT Assertion: {assertion}")
Assertion Expiration
JWT assertions should have a short expiration time (5 minutes recommended). This limits the window for potential replay attacks.
Step 3: Exchange Assertion for Access Token
Send the JWT assertion to CHeKT's token endpoint to receive an access token.
Request
curl -X POST https://auth.chekt.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
-d "assertion=YOUR_JWT_ASSERTION"
Parameters:
| Parameter | Value |
|---|---|
grant_type | urn:ietf:params:oauth:grant-type:jwt-bearer |
assertion | Your signed JWT assertion token |
Response
Success (200 OK):
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
Response Fields:
| Field | Description |
|---|---|
access_token | The access token to use for API requests |
token_type | Always "Bearer" |
expires_in | Token lifetime in seconds (typically 3600 = 1 hour) |
Step 4: Use Access Token for API Requests
Include the access token in the Authorization header for all Event API requests.
Request Headers
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
Example: Send Event
curl -X POST https://api.chekt.com/partner/v1/events \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"version": "1.0",
"location_id": "Z6RSOG",
"recorder_id": "Z6RANV",
"camera_id": "2fe519b4-2438-4aa1-b051-87cf22bb",
"event_id": "1763603245534315",
"event_type": "alarm",
"event_status": "active",
"event_time": "2025-11-20T01:46:25.534Z",
"sent_at": "2025-11-20T01:46:28.534Z",
"should_signal_to_monitoring_center": true,
"upload_snapshot_count": 1,
"upload_short_mp4": false,
"upload_event_mp4": true,
"payload": {}
}'
Token Management
Token Caching
Access tokens are valid for a limited time (typically 1 hour). To optimize performance:
- Cache the access token in memory
- Reuse the token until it expires
- Generate a new token only when the current one expires
Implementation Example:
class EventAPIClient {
constructor(clientId, secretKey) {
this.clientId = clientId;
this.secretKey = secretKey;
this.accessToken = null;
this.tokenExpiry = 0;
}
async getAccessToken() {
// Check if current token is still valid
if (this.accessToken && Date.now() < this.tokenExpiry) {
return this.accessToken;
}
// Generate new JWT assertion
const assertion = this.createJWTAssertion();
// Exchange for access token
const response = await fetch('https://auth.chekt.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${assertion}`
});
const data = await response.json();
// Cache token with safety margin (refresh 1 minute early)
this.accessToken = data.access_token;
this.tokenExpiry = Date.now() + (data.expires_in * 1000) - 60000;
return this.accessToken;
}
createJWTAssertion() {
// Implementation from Step 2
// ...
}
async sendEvent(eventData) {
const token = await this.getAccessToken();
return fetch('https://api.chekt.com/partner/v1/events', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(eventData)
});
}
}
Token Refresh Strategy
When an access token expires:
- You'll receive a
401 Unauthorizedresponse - Generate a new JWT assertion
- Request a new access token
- Retry the API request with the new token
Automatic Retry
Implement automatic token refresh and request retry in your API client to handle token expiration gracefully.
Authentication Errors
Common Error Responses
401 Unauthorized
{
"error": "Unauthorized",
"message": "Invalid or expired access token"
}
Solution: Generate a new access token using a fresh JWT assertion
403 Forbidden
{
"error": "Forbidden",
"message": "Insufficient permissions for event ingestion"
}
Solution: Verify your Auth Application has event ingestion permissions
400 Bad Request - Invalid Assertion
{
"error": "invalid_grant",
"error_description": "Invalid JWT assertion"
}
Possible Causes:
- JWT signature is invalid (wrong secret key)
- JWT has expired
- JWT claims are malformed
audclaim doesn't match auth server
Security Best Practices
Complete Authentication Example
Here's a complete example of authenticating and sending an event:
const jwt = require('jsonwebtoken');
const axios = require('axios');
// Configuration
const CLIENT_ID = process.env.CHEKT_EVENT_CLIENT_ID;
const SECRET_KEY = process.env.CHEKT_EVENT_SECRET_KEY;
const AUTH_SERVER = 'https://auth.chekt.com';
const API_BASE = 'https://api.chekt.com';
// Token cache
let cachedToken = null;
let tokenExpiry = 0;
// Generate JWT assertion
function createAssertion() {
return jwt.sign(
{
iss: CLIENT_ID,
sub: CLIENT_ID,
aud: AUTH_SERVER,
exp: Math.floor(Date.now() / 1000) + 300,
iat: Math.floor(Date.now() / 1000),
jti: require('crypto').randomUUID()
},
SECRET_KEY,
{ algorithm: 'RS256' }
);
}
// Get access token (with caching)
async function getAccessToken() {
// Return cached token if still valid
if (cachedToken && Date.now() < tokenExpiry) {
return cachedToken;
}
// Generate new assertion
const assertion = createAssertion();
// Exchange for access token
const response = await axios.post(
`${AUTH_SERVER}/oauth/token`,
new URLSearchParams({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: assertion
}),
{
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}
);
// Cache token
cachedToken = response.data.access_token;
tokenExpiry = Date.now() + (response.data.expires_in * 1000) - 60000; // Refresh 1 min early
return cachedToken;
}
// Send event
async function sendEvent(eventData) {
const accessToken = await getAccessToken();
try {
const response = await axios.post(
`${API_BASE}/partner/v1/events`,
eventData,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
} catch (error) {
// Handle 401 by refreshing token and retrying
if (error.response?.status === 401) {
cachedToken = null; // Invalidate cache
const newToken = await getAccessToken();
const retryResponse = await axios.post(
`${API_BASE}/partner/v1/events`,
eventData,
{
headers: {
'Authorization': `Bearer ${newToken}`,
'Content-Type': 'application/json'
}
}
);
return retryResponse.data;
}
throw error;
}
}
// Usage
const eventData = {
version: "1.0",
location_id: "Z6RSOG",
recorder_id: "Z6RANV",
camera_id: "2fe519b4-2438-4aa1-b051-87cf22bb",
event_id: "1763603245534315",
event_type: "alarm",
event_status: "active",
event_time: "2025-11-20T01:46:25.534Z",
sent_at: "2025-11-20T01:46:28.534Z",
should_signal_to_monitoring_center: true,
upload_snapshot_count: 1,
upload_short_mp4: false,
upload_event_mp4: true,
payload: {}
};
sendEvent(eventData)
.then(result => console.log('Event sent:', result))
.catch(error => console.error('Error:', error.response?.data || error.message));
Next Steps
Now that you understand authentication, you can start sending events:
Next Steps
Support
For authentication issues or questions:
- Email: support@chekt.com
- Documentation: developer.chekt.com