Skip to main content

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

  1. Obtain Token - Call the login endpoint with credentials
  2. Include Token - Add the token to request headers
  3. 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:

FieldTypeDescription
usernamestringYour email address
passwordstringYour 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 CodeDescriptionSolution
401Invalid credentialsCheck email/password
401Token expiredObtain a new token
403ForbiddenCheck user permissions
422Validation errorCheck request format

Security Best Practices

  1. Never expose tokens in client-side code or logs
  2. Use HTTPS for all API requests
  3. Store tokens securely (e.g., HTTP-only cookies, secure storage)
  4. Rotate tokens regularly for long-running applications
  5. Implement token refresh before expiration