REST API Authentication
Learn how to authenticate your requests to the Layer One REST API. Obtain an access token by authenticating with the authorization server, enabling secure and authorized access to all API endpoints.
Authentication Endpoints
Production
https://api.integrated-projects.com/v1/authentication/token
Staging
https://staging-api.integrated-projects.com/v1/authentication/token
Authentication Flow
The Layer One API uses OAuth 2.0 client credentials flow for authentication:
- Request credentials from IPX team to retrieve client ID and client secret
- App makes an HTTP call to an OAuth REST endpoint and provides its credentials
- An access token is returned to your app
- In making subsequent calls to various APIs, your app includes the access token in a request header
Creating an Access Token
Request Method
POST /v1/authentication/token
Headers
Authorization: Basic <BASE64_ENCODED_CLIENT_ID_AND_SECRET>
Content-Type: application/json
Request Body
{
"client_id": "<client_id>",
"client_secret": "<client_secret>",
"grant_type": "client_credentials"
}
Parameters
Parameter | Type | Description |
---|---|---|
client_id | string | Client ID of the app |
client_secret | string | Client secret of the app |
grant_type | string | Returns a access token if type is client_credentials |
Response
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsIngrOVd4R1dUR1ZeBeKNhS8aq2URXM2qUzxBEUVAM...",
"token_type": "Bearer",
"expires_in": 3599
}
Response Parameters
Parameter | Type | Description |
---|---|---|
access_token | string | Access token |
token_type | string | Will always be Bearer |
expires_in | number | Access token expiration time (in seconds) |
Using the Access Token
Include the access token in the Authorization
header of all subsequent API requests:
curl -X GET \
https://api.integrated-projects.com/v1/projects \
-H "Authorization: Bearer your-access-token-here" \
-H "Content-Type: application/json"
Revoking an Access Token
You can revoke an access token when it’s no longer needed, such as during logout or security incidents.
Request Method
POST /v1/authentication/revoke
Endpoints
- Production:
https://api.integrated-projects.com/v1/authentication/revoke
- Staging:
https://staging-api.integrated-projects.com/v1/authentication/revoke
Request Body
{
"client_id": "<client_id>",
"access_token": "<access_token>"
}
Parameters
Parameter | Type | Description |
---|---|---|
client_id | string | Client ID of the app |
access_token | string | Access token to revoke |
Response
Success Response:
{
"success": true,
"error": null
}
Error Response:
{
"success": false,
"error": "Error message if applicable"
}
Example Request
curl -X POST \
https://api.integrated-projects.com/v1/authentication/revoke \
-H "Content-Type: application/json" \
-d '{
"client_id": "4cf37e68-22a1-43be-ab7c-88ff51c4d903",
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIs..."
}'
Introspecting an Access Token
View access token details by supplying the token and client_id. This is useful for validating tokens and checking their expiration status.
Request Method
POST /v1/authentication/introspect
Endpoints
- Production:
https://api.integrated-projects.com/v1/authentication/introspect
- Staging:
https://staging-api.integrated-projects.com/v1/authentication/introspect
Request Body
{
"client_id": "<client_id>",
"access_token": "<access_token>"
}
Parameters
Parameter | Type | Description |
---|---|---|
client_id | string | Client ID |
access_token | string | Access token |
Response
Success Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIs...",
"token_type": "Bearer",
"expires_at": "2025-06-03T11:42:44.840Z",
"revoked": false
}
Error Response:
{
"error": "invalid_credentials"
}
Response Parameters
Parameter | Type | Description |
---|---|---|
access_token | string | Access token |
token_type | string | Bearer |
expires_at | string | Timestamp of token expiration |
revoked | boolean | true/false |
Example Request
curl -X POST \
https://api.integrated-projects.com/v1/authentication/introspect \
-H "Content-Type: application/json" \
-d '{
"client_id": "4cf37e68-22a1-43be-ab7c-88ff51c4d903",
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIs..."
}'
Complete Authentication Example
Step 1: Encode Credentials
First, encode your client ID and secret in Base64 format:
# Format: client_id:client_secret
echo -n "your_client_id:your_client_secret" | base64
Step 2: Request Access Token
curl -X POST \
https://api.integrated-projects.com/v1/authentication/token \
-H "Authorization: Basic <BASE64_ENCODED_CLIENT_ID_AND_SECRET>" \
-H "Content-Type: application/json" \
-d '{
"client_id": "your_client_id",
"client_secret": "your_client_secret",
"grant_type": "client_credentials"
}'
Step 3: Use Access Token
curl -X GET \
https://api.integrated-projects.com/v1/projects \
-H "Authorization: Bearer your-access-token-here" \
-H "Content-Type: application/json"
Code Examples
JavaScript/Node.js
const axios = require('axios');
// Step 1: Get access token
const getAccessToken = async (clientId: string, clientSecret: string): Promise<string> => {
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
const response = await axios.post(
'https://api.integrated-projects.com/v1/authentication/token',
{
client_id: clientId,
client_secret: clientSecret,
grant_type: 'client_credentials'
},
{
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
}
}
);
return response.data.access_token;
};
// Step 2: Use access token for API calls
const makeAPICall = async (accessToken: string) => {
const response = await axios.get(
'https://api.integrated-projects.com/v1/projects',
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
};
// Step 3: Revoke access token when done
const revokeAccessToken = async (clientId: string, accessToken: string): Promise<boolean> => {
const response = await axios.post(
'https://api.integrated-projects.com/v1/authentication/revoke',
{
client_id: clientId,
access_token: accessToken
},
{
headers: {
'Content-Type': 'application/json'
}
}
);
return response.data.success;
};
// Step 4: Introspect access token
const introspectAccessToken = async (clientId: string, accessToken: string) => {
const response = await axios.post(
'https://api.integrated-projects.com/v1/authentication/introspect',
{
client_id: clientId,
access_token: accessToken
},
{
headers: {
'Content-Type': 'application/json'
}
}
);
return response.data;
};
// Usage
const clientId = process.env.IPX_CLIENT_ID;
const clientSecret = process.env.IPX_CLIENT_SECRET;
const accessToken = await getAccessToken(clientId, clientSecret);
const projects = await makeAPICall(accessToken);
// Check token status
const tokenInfo = await introspectAccessToken(clientId, accessToken);
console.log('Token expires at:', tokenInfo.expires_at);
console.log('Token revoked:', tokenInfo.revoked);
// Revoke token when done
await revokeAccessToken(clientId, accessToken);
Python
import requests
import base64
import os
def get_access_token(client_id: str, client_secret: str) -> str:
# Encode credentials
credentials = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()
headers = {
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json'
}
data = {
'client_id': client_id,
'client_secret': client_secret,
'grant_type': 'client_credentials'
}
response = requests.post(
'https://api.integrated-projects.com/v1/authentication/token',
headers=headers,
json=data
)
return response.json()['access_token']
def make_api_call(access_token: str):
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
response = requests.get(
'https://api.integrated-projects.com/v1/projects',
headers=headers
)
return response.json()
def revoke_access_token(client_id: str, access_token: str) -> bool:
data = {
'client_id': client_id,
'access_token': access_token
}
response = requests.post(
'https://api.integrated-projects.com/v1/authentication/revoke',
headers={'Content-Type': 'application/json'},
json=data
)
return response.json()['success']
def introspect_access_token(client_id: str, access_token: str):
data = {
'client_id': client_id,
'access_token': access_token
}
response = requests.post(
'https://api.integrated-projects.com/v1/authentication/introspect',
headers={'Content-Type': 'application/json'},
json=data
)
return response.json()
# Usage
client_id = os.getenv('IPX_CLIENT_ID')
client_secret = os.getenv('IPX_CLIENT_SECRET')
access_token = get_access_token(client_id, client_secret)
projects = make_api_call(access_token)
# Check token status
token_info = introspect_access_token(client_id, access_token)
print(f"Token expires at: {token_info['expires_at']}")
print(f"Token revoked: {token_info['revoked']}")
# Revoke token when done
revoke_success = revoke_access_token(client_id, access_token)
Security Best Practices
Credential Security
- Never expose client credentials in client-side code
- Use environment variables to store client ID and secret
- Rotate credentials regularly for enhanced security
- Use different credentials for different environments (dev, staging, production)
Environment Configuration
# .env file
IPX_CLIENT_ID=your_client_id_here
IPX_CLIENT_SECRET=your_client_secret_here
IPX_BASE_URL=https://api.integrated-projects.com/v1
Token Management
- Store tokens securely in memory or secure storage
- Handle token expiration by implementing automatic refresh
- Monitor token usage and implement proper error handling
- Revoke tokens when they’re no longer needed (logout, security incidents)
- Use introspection to validate token status and expiration
Testing Authentication
You can test your authentication setup by making a request to get an access token:
curl -X POST \
https://api.integrated-projects.com/v1/authentication/token \
-H "Authorization: Basic <BASE64_ENCODED_CLIENT_ID_AND_SECRET>" \
-H "Content-Type: application/json" \
-d '{
"client_id": "your_client_id",
"client_secret": "your_client_secret",
"grant_type": "client_credentials"
}'
Success Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIs...",
"token_type": "Bearer",
"expires_in": 3599
}
Error Response:
{
"error": "invalid_client",
"error_description": "Invalid client credentials"
}
Token Expiration and Refresh
Access tokens have a limited lifespan (typically 1 hour). When a token expires, you’ll need to request a new one:
const handleTokenExpiration = async (clientId: string, clientSecret: string) => {
try {
// Check if token is still valid
const tokenInfo = await introspectAccessToken(clientId, currentToken);
if (tokenInfo.revoked || new Date(tokenInfo.expires_at) < new Date()) {
// Token is expired or revoked, get a new one
const newToken = await getAccessToken(clientId, clientSecret);
return await makeAPICall(newToken);
}
// Token is still valid, use it
const response = await makeAPICall(currentToken);
return response;
} catch (error) {
if (error.status === 401) {
// Token expired, get a new one
const newToken = await getAccessToken(clientId, clientSecret);
// Retry the API call with new token
return await makeAPICall(newToken);
}
throw error;
}
};
Troubleshooting
Common Authentication Errors
Error | Description | Solution |
---|---|---|
invalid_client | Invalid client credentials | Verify your client ID and secret |
unauthorized | Missing or invalid authorization header | Check Base64 encoding of credentials |
invalid_grant | Invalid grant type | Ensure grant_type is “client_credentials” |
401 Unauthorized | Expired or invalid access token | Request a new access token |
Getting Help
If you’re experiencing authentication issues:
- Verify your client ID and secret are correct
- Check that you’re using the correct endpoint (production vs staging)
- Ensure your Base64 encoding is correct
- Verify the request body format matches the specification
- Contact support if issues persist