API Authentication
The SEO Platform API uses JWT (JSON Web Tokens) for authentication. This guide explains how to obtain and use access tokens.
Authentication Flow
- Obtain Token - Call the login endpoint with credentials
- Include Token - Add the token to request headers
- Refresh Token - Tokens expire after 30 minutes; obtain a new one
Obtaining an Access Token
Login Endpoint
POST /api/v1/auth/login
Content-Type: application/x-www-form-urlencoded
Request Body:
| Field | Type | Description |
|---|---|---|
username | string | Your email address |
password | string | Your password |
Python Example
import requests
response = requests.post(
"https://seo.bedmar.dk/api/v1/auth/login",
data={
"username": "user@example.com",
"password": "your-password"
}
)
token_data = response.json()
access_token = token_data["access_token"]
print(f"Access Token: {access_token}")
JavaScript/TypeScript Example
const response = await fetch('https://seo.bedmar.dk/api/v1/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
username: 'user@example.com',
password: 'your-password',
}),
});
const { access_token } = await response.json();
console.log('Access Token:', access_token);
cURL Example
curl -X POST "https://seo.bedmar.dk/api/v1/auth/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=user@example.com&password=your-password"
Using the Access Token
Include the token in the Authorization header for all authenticated requests:
Authorization: Bearer YOUR_ACCESS_TOKEN
Python Example
import requests
headers = {
"Authorization": f"Bearer {access_token}"
}
# Get current user
response = requests.get(
"https://seo.bedmar.dk/api/v1/users/me",
headers=headers
)
user = response.json()
print(f"Logged in as: {user['email']}")
JavaScript/TypeScript Example
const headers = {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json',
};
// Get current user
const userResponse = await fetch('https://seo.bedmar.dk/api/v1/users/me', {
headers,
});
const user = await userResponse.json();
console.log('Logged in as:', user.email);
Token Expiration
Access tokens expire after 30 minutes. When a token expires, you'll receive a 401 Unauthorized response:
{
"detail": "Token has expired"
}
To continue making requests, obtain a new token using the login endpoint.
Handling Token Refresh (Python)
import requests
from datetime import datetime, timedelta
class APIClient:
def __init__(self, base_url, email, password):
self.base_url = base_url
self.email = email
self.password = password
self.access_token = None
self.token_expires = None
def _ensure_token(self):
if not self.access_token or datetime.now() >= self.token_expires:
self._login()
def _login(self):
response = requests.post(
f"{self.base_url}/api/v1/auth/login",
data={"username": self.email, "password": self.password}
)
data = response.json()
self.access_token = data["access_token"]
# Set expiry 5 minutes before actual expiry for safety
self.token_expires = datetime.now() + timedelta(minutes=25)
def get(self, endpoint):
self._ensure_token()
return requests.get(
f"{self.base_url}{endpoint}",
headers={"Authorization": f"Bearer {self.access_token}"}
)
Handling Token Refresh (TypeScript)
class APIClient {
private baseUrl: string;
private email: string;
private password: string;
private accessToken: string | null = null;
private tokenExpires: Date | null = null;
constructor(baseUrl: string, email: string, password: string) {
this.baseUrl = baseUrl;
this.email = email;
this.password = password;
}
private async ensureToken(): Promise<void> {
if (!this.accessToken || !this.tokenExpires || new Date() >= this.tokenExpires) {
await this.login();
}
}
private async login(): Promise<void> {
const response = await fetch(`${this.baseUrl}/api/v1/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ username: this.email, password: this.password }),
});
const data = await response.json();
this.accessToken = data.access_token;
// Set expiry 5 minutes before actual expiry for safety
this.tokenExpires = new Date(Date.now() + 25 * 60 * 1000);
}
async get<T>(endpoint: string): Promise<T> {
await this.ensureToken();
const response = await fetch(`${this.baseUrl}${endpoint}`, {
headers: { 'Authorization': `Bearer ${this.accessToken}` },
});
return response.json();
}
}
Error Responses
| Status Code | Description | Solution |
|---|---|---|
| 401 | Invalid credentials | Check email/password |
| 401 | Token expired | Obtain a new token |
| 403 | Forbidden | Check user permissions |
| 422 | Validation error | Check request format |
Security Best Practices
- Never expose tokens in client-side code or logs
- Use HTTPS for all API requests
- Store tokens securely (e.g., HTTP-only cookies, secure storage)
- Rotate tokens regularly for long-running applications
- Implement token refresh before expiration
Related Topics
- API Overview - General API information
- API Endpoints - Full endpoint reference