From 92f0e7ea25eccb39d08d2cae5977cd9a1bc56018 Mon Sep 17 00:00:00 2001 From: cclohmar Date: Wed, 15 Jul 2026 17:59:57 +0000 Subject: [PATCH] chore: update Postman collection and guide with policy endpoints Postman collection now has 12 endpoints: - Health Check, List/Get/Bulk Create/Delete Users - List/Create/Get/Update/Delete Policy - Verify Policy (dry-run) - Get User Policies POSTMAN_GUIDE.md updated with all endpoints, examples, policy field reference, matching rules, and testing workflow. --- POSTMAN_GUIDE.md | 339 ++++++++++++++++++--------- authelia-api.postman_collection.json | 300 +++++++++++++++++++++--- 2 files changed, 500 insertions(+), 139 deletions(-) diff --git a/POSTMAN_GUIDE.md b/POSTMAN_GUIDE.md index 9947982..a420d34 100644 --- a/POSTMAN_GUIDE.md +++ b/POSTMAN_GUIDE.md @@ -1,115 +1,182 @@ -# Authelia API - Postman Collection +# Authelia API — Postman Collection Guide -This directory contains Postman files for testing and interacting with the Authelia API. +Postman files for testing and interacting with the Authelia API (user management + access control policies). ## Files -- `authelia-api.postman_collection.json` - Main Postman collection with all API endpoints -- `authelia-api.postman_environment.json` - Environment variables for easy configuration -- `src/test_bulk.json` - Example request body for bulk user creation +| File | Description | +|------|-------------| +| `authelia-api.postman_collection.json` | Collection with all 12 API endpoints | +| `authelia-api.postman_environment.json` | Environment variables (`base_url`, `bearer_token`) | -## Setup Instructions +## Setup ### 1. Import into Postman -1. Open Postman -2. Click **Import** button -3. Select both the collection and environment files -4. Click **Import** +1. Open Postman → **Import** → select both files → **Import** ### 2. Configure Environment -1. In Postman, select the **"Authelia API"** environment from the environment dropdown (top-right) -2. Click the eye icon next to the environment name -3. Set the following variables: +1. Select **"Authelia API"** environment from the dropdown (top-right) +2. Click the eye icon → set variables: -| Variable | Value | Description | -|----------|-------|-------------| -| `base_url` | `http://127.0.0.1:8080` | API base URL (default) | -| `bearer_token` | Your session.secret | **Required** - Get from Authelia config | +| Variable | Default | Description | +|----------|---------|-------------| +| `base_url` | `http://127.0.0.1:8080` | API address | +| `bearer_token` | *(your token)* | `session.secret` from Authelia config | ### 3. Get Your Bearer Token -The initial bearer token is your Authelia `session.secret`: - ```bash -# Extract from Authelia configuration -grep -A2 "session:" /opt/authelia/configuration.yml | grep "secret:" | awk '{print $2}' +# Extract from Authelia configuration.yml +grep -A2 "session:" /config/configuration.yml | grep "secret:" | awk '{print $2}' ``` -Example token: `5DdUKe12k6niaaekpTeB0H35A48xmTWBWJcI3AOoqPA=` +Example: `5DdUKe12k6niaaekpTeB0H35A48xmTWBWJcI3AOoqPA=` -**Security Note:** This token provides full API access. Keep it secure! +> **Security:** This token grants full API access. Keep it secure. + +--- ## API Endpoints -### Health Check -- **GET** `/api/health` -- No authentication required -- Returns API status and version +### User Management -### Bulk Create Users -- **POST** `/api/users/bulk` -- Requires Bearer token -- Creates multiple users with auto-generated passwords -- Example request body in `src/test_bulk.json` +| Method | Endpoint | Description | +|--------|----------|-------------| +| `GET` | `/api/health` | Health check *(no auth)* | +| `GET` | `/api/users` | List all users | +| `GET` | `/api/users/{username}` | Get single user | +| `POST` | `/api/users/bulk` | Bulk create users (max 1000) | +| `DELETE` | `/api/users/{username}` | Delete user | -### List Users -- **GET** `/api/users` -- Requires Bearer token -- Lists all users in the system +### Policy Management -### Delete User -- **DELETE** `/api/users/{username}` -- Requires Bearer token -- Deletes a user by username +| Method | Endpoint | Description | +|--------|----------|-------------| +| `GET` | `/api/policies` | List all policies | +| `POST` | `/api/policies` | Create policy | +| `GET` | `/api/policies/{policy_id}` | Get single policy | +| `PUT` | `/api/policies/{policy_id}` | Update policy | +| `DELETE` | `/api/policies/{policy_id}` | Delete policy | +| `POST` | `/api/policies/verify` | Dry-run policy matching | +| `GET` | `/api/users/{username}/policies` | Get policies for a user | -## Testing Workflow +--- -1. **Health Check**: Verify API is running -2. **Bulk Create**: Add test users (see example below) -3. **List Users**: Confirm users were created -4. **Delete User**: Clean up test users +## Examples -### Example: Create Test Users - -Use the pre-configured request in the collection, or modify the body: +### Create Policy ```json +POST /api/policies +Authorization: Bearer + +{ + "name": "Admin Dashboard Restrictions", + "domain": ["*.example.com", "secure.example.com"], + "resources": ["^/admin/.*$"], + "methods": ["POST", "PUT", "DELETE"], + "subjects": ["group:admins", "user:admin"], + "policy": "two_factor" +} +``` + +**Response `201`:** +```json +{ + "id": "pol_93f8s2", + "name": "Admin Dashboard Restrictions", + "domain": ["*.example.com", "secure.example.com"], + "resources": ["^/admin/.*$"], + "methods": ["POST", "PUT", "DELETE"], + "subjects": ["group:admins", "user:admin"], + "policy": "two_factor", + "created_at": "2026-07-15 12:00:00", + "updated_at": "2026-07-15 12:00:00" +} +``` + +### Verify Policy (Dry-run) + +Test how a request would evaluate against your policies: + +```json +POST /api/policies/verify +Authorization: Bearer + +{ + "domain": "secure.example.com", + "path": "/admin/dashboard", + "method": "POST", + "username": "test.user1", + "groups": ["developers", "admins"] +} +``` + +**Response `200` (matched):** +```json +{ + "matched": true, + "policy_id": "pol_93f8s2", + "policy_name": "Admin Dashboard Restrictions", + "action_required": "two_factor" +} +``` + +**Response `200` (no match):** +```json +{ + "matched": false +} +``` + +### Get User Policies + +Retrieve all policies applicable to a specific user: + +```json +GET /api/users/john.doe/policies +Authorization: Bearer +``` + +**Response `200`:** +```json +[ + { + "policy_id": "pol_93f8s2", + "name": "Admin Dashboard Restrictions", + "match_reason": "Matched via group membership: admins", + "policy": "two_factor", + "domain": ["*.example.com"], + "resources": ["^/admin/.*$"] + } +] +``` + +### Create Users (Bulk) + +```json +POST /api/users/bulk +Authorization: Bearer + { "users": [ { - "username": "test.user1", - "display_name": "Test User One", - "email": "test1@example.com", - "groups": ["users", "developers"] - }, - { - "username": "test.user2", - "display_name": "Test User Two", - "email": "test2@example.com", - "groups": ["users"] + "username": "john.doe", + "display_name": "John Doe", + "email": "john.doe@example.com", + "groups": ["users", "admins"] } ] } ``` -## Response Examples - -### Health Check -```json -{ - "status": "ok", - "version": "dev", - "time": "2026-04-02T00:00:00Z" -} -``` - -### Bulk Create Success +**Response `200`:** ```json { "success": true, - "created": 2, + "created": 1, "users": [ { "username": "john.doe", @@ -122,47 +189,107 @@ Use the pre-configured request in the collection, or modify the body: } ``` -### List Users +### Get Single User + ```json -[ - { - "username": "john.doe", - "display_name": "John Doe", - "email": "john.doe@example.com", - "groups": ["users", "admins"], - "disabled": false, - "created_at": "2026-04-02 00:00:00", - "updated_at": "2026-04-02 00:00:00" - } -] +GET /api/users/john.doe +Authorization: Bearer ``` +**Response `200`:** +```json +{ + "username": "john.doe", + "display_name": "John Doe", + "email": "john.doe@example.com", + "groups": ["users", "admins"], + "disabled": false, + "created_at": "2026-07-15 12:00:00", + "updated_at": "2026-07-15 12:00:00" +} +``` + +### Delete User + +```json +DELETE /api/users/john.doe +Authorization: Bearer +``` + +**Response `200`:** +```json +{ + "success": true, + "message": "User john.doe deleted" +} +``` + +### Health Check + +```json +GET /api/health +``` + +**Response `200`:** +```json +{ + "status": "ok", + "version": "dev", + "time": "2026-07-15T12:00:00Z" +} +``` + +--- + +## Policy Fields Reference + +| Field | Required | Type | Description | +|-------|----------|------|-------------| +| `name` | ✅ | string | Human-readable identifier | +| `domain` | ✅ | `[]string` | Domain patterns (supports `*` wildcards) | +| `resources` | no | `[]string` | URL path regex patterns | +| `methods` | no | `[]string` | HTTP methods (empty = all) | +| `subjects` | no | `[]string` | `user:` or `group:` patterns | +| `policy` | ✅ | string | `bypass`, `one_factor`, `two_factor`, or `deny` | + +### Matching Rules + +- **Domain**: glob-style (`*.example.com` matches `secure.example.com`) +- **Resources**: regex matched against URL paths +- **Methods**: exact match (empty array = all methods pass) +- **Subjects**: matched against user's username and group memberships +- **Policy**: the required auth level if all criteria match + +--- + +## Testing Workflow + +``` +1. Health Check → Verify API is running +2. Create Policy → Define an access control rule +3. Get Policies → Confirm it was created +4. Verify Policy → Dry-run a request against it +5. Create Users → Add test users (bulk) +6. Get User Policies → Check which policies apply to user +7. Clean up → Delete users and policies +``` + +--- + ## Troubleshooting -### 401 Unauthorized -- Check that `bearer_token` is set in environment -- Verify token matches Authelia `session.secret` -- Ensure `Authorization` header is present +| Error | Likely Cause | Fix | +|-------|-------------|-----| +| `401` | Missing/wrong Bearer token | Check `bearer_token` env var; verify it matches `session.secret` | +| `404` | User or policy not found | Check spelling; list first to confirm ID | +| `400` | Invalid request body | Validate JSON syntax; check required fields | +| Connection refused | API not running | `docker ps`; check `docker compose up -d` | +| Policy `400` | Invalid policy value | Must be one of: `bypass`, `one_factor`, `two_factor`, `deny` | -### Connection Refused -- Verify Authelia API is running: `systemctl status authelia-api` -- Check API port: Default is `127.0.0.1:8080` -- Ensure firewall allows local connections +--- -### 400 Bad Request -- Validate JSON request body format -- Check required fields: `username`, `display_name`, `email` -- Ensure email contains '@' symbol +## Related -## Next Steps - -1. Test API with actual user data -2. Configure SMTP for email onboarding (if needed) -3. Set up monitoring/alerting for API health -4. Consider rotating bearer tokens for production - -## Related Resources - -- [Authelia API Source Code](../src/) -- [Installation Guide](README.md) +- [OpenAPI Spec](openapi.yml) — Full API specification +- [Source Code](src/) — Go source - [Authelia Documentation](https://www.authelia.com/) diff --git a/authelia-api.postman_collection.json b/authelia-api.postman_collection.json index e6ba6c0..8b94a20 100644 --- a/authelia-api.postman_collection.json +++ b/authelia-api.postman_collection.json @@ -1,7 +1,7 @@ { "info": { - "name": "Authelia API API", - "description": "Postman collection for Authelia API REST API\n\nThis API provides a \"Source of Truth\" for Authelia user management with SQLite backend, bulk user onboarding, and automatic synchronization with Authelia's `users_database.yml` file.\n\n## Authentication\n- Use Bearer token authentication\n- Initial token: `session.secret` from Authelia configuration.yml\n- Header: `Authorization: Bearer `\n\n## Base URL\n- Default: `http://127.0.0.1:8080`\n- Can be changed via `--listen` flag\n\n## Quick Start\n1. Install Authelia API using `install.sh`\n2. Start the service: `systemctl start authelia-api`\n3. Get your session.secret from `/opt/authelia/configuration.yml`\n4. Use this collection with the token as environment variable\n\n## Notes\n- All user passwords are auto-generated as secure placeholders\n- Changes trigger automatic sync to Authelia YAML file\n- SMTP onboarding emails available if configured", + "name": "Authelia API", + "description": "Postman collection for Authelia API — user management and access control policy management.\n\n## Authentication\n- Use Bearer token authentication\n- Initial token: `session.secret` from Authelia configuration.yml\n- Header: `Authorization: Bearer `\n\n## Base URL\n- Default: `http://127.0.0.1:8080`\n\n## Quick Start\n1. Start the container: `docker compose up -d`\n2. Get Bearer token from Authelia config's `session.secret`\n3. Set `bearer_token` in environment\n4. Start with Health Check → try Bulk Create → manage policies\n\n## Notes\n- All user passwords are auto-generated\n- Changes trigger automatic sync to Authelia YAML file\n- SMTP onboarding emails available if configured", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ @@ -20,7 +20,52 @@ "host": ["{{base_url}}"], "path": ["api", "health"] }, - "description": "Health check endpoint to verify API is running. No authentication required." + "description": "Health check endpoint. No authentication required.\n\nReturns API status, version, and current timestamp." + }, + "response": [] + }, + { + "name": "List Users", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "url": { + "raw": "{{base_url}}/api/users", + "host": ["{{base_url}}"], + "path": ["api", "users"] + }, + "description": "List all users in the system.\n\nReturns an array of user objects with username, display_name, email, groups, disabled status, and timestamps." + }, + "response": [] + }, + { + "name": "Get User", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "url": { + "raw": "{{base_url}}/api/users/:username", + "host": ["{{base_url}}"], + "path": ["api", "users", ":username"], + "variable": [ + { + "key": "username", + "value": "john.doe", + "description": "Username to retrieve" + } + ] + }, + "description": "Get a single user by username.\n\n**Path Parameter:**\n- `username` — the username to look up\n\nReturns 404 if user not found." }, "response": [] }, @@ -52,26 +97,7 @@ "host": ["{{base_url}}"], "path": ["api", "users", "bulk"] }, - "description": "Create multiple users in a single request. Passwords are automatically generated and returned in the response.\n\n**Limits:**\n- Max 1000 users per request\n- Username, display_name, and email are required\n- Email must contain '@' symbol\n\n**Response includes:**\n- `success`: boolean indicating if any users were created\n- `created`: count of successfully created users\n- `users`: array with status and placeholder_password for each user" - }, - "response": [] - }, - { - "name": "List Users", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - } - ], - "url": { - "raw": "{{base_url}}/api/users", - "host": ["{{base_url}}"], - "path": ["api", "users"] - }, - "description": "List all users in the system with pagination support.\n\n**Query Parameters:**\n- `page`: page number (default: 1)\n- `page_size`: items per page (default: 50)\n\n**Note:** Pagination is implemented but currently returns all users. Future versions will support proper pagination." + "description": "Create multiple users in a single request. Passwords are auto-generated.\n\n**Limits:**\n- Max 1000 users per batch\n- `username`, `display_name`, `email` required\n\n**Response includes:**\n- `success`: boolean\n- `created`: count of successfully created users\n- `users`: array with `placeholder_password` and `status` per user" }, "response": [] }, @@ -91,13 +117,213 @@ "path": ["api", "users", ":username"], "variable": [ { - "key": ":username", + "key": "username", "value": "john.doe", "description": "Username to delete" } ] }, - "description": "Delete a user by username. Triggers automatic sync to update Authelia's YAML file.\n\n**Returns:**\n- `success`: boolean\n- `message`: confirmation message" + "description": "Delete a user by username. Triggers automatic YAML sync.\n\nReturns 404 if user not found." + }, + "response": [] + }, + { + "name": "List Policies", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "url": { + "raw": "{{base_url}}/api/policies", + "host": ["{{base_url}}"], + "path": ["api", "policies"] + }, + "description": "List all access control policies.\n\nReturns an array of policy objects with id, name, domain, resources, methods, subjects, policy level, and timestamps." + }, + "response": [] + }, + { + "name": "Create Policy", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Admin Dashboard Restrictions\",\n \"domain\": [\"*.example.com\", \"secure.example.com\"],\n \"resources\": [\"^/admin/.*$\"],\n \"methods\": [\"POST\", \"PUT\", \"DELETE\"],\n \"subjects\": [\"group:admins\", \"user:admin\"],\n \"policy\": \"two_factor\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/policies", + "host": ["{{base_url}}"], + "path": ["api", "policies"] + }, + "description": "Create a new access control policy rule.\n\n**Required fields:** `name`, `domain` (array with at least 1 pattern), `policy`\n\n**Policy levels:** `bypass`, `one_factor`, `two_factor`, `deny`\n\n**Domain patterns** support wildcards: `*.example.com`\n\n**Resources** are regex patterns matched against URL paths.\n\n**Subjects** can be `user:` or `group:`.\n\nReturns the created policy with a generated `id` (e.g. `pol_93f8s2`)." + }, + "response": [] + }, + { + "name": "Get Policy", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "url": { + "raw": "{{base_url}}/api/policies/:policy_id", + "host": ["{{base_url}}"], + "path": ["api", "policies", ":policy_id"], + "variable": [ + { + "key": "policy_id", + "value": "pol_93f8s2", + "description": "Policy ID (e.g. pol_93f8s2)" + } + ] + }, + "description": "Get a single policy by its unique ID.\n\nReturns 404 if policy not found." + }, + "response": [] + }, + { + "name": "Update Policy", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Admin Dashboard Restrictions\",\n \"domain\": [\"*.example.com\"],\n \"resources\": [\"^/admin/.*$\"],\n \"methods\": [\"POST\", \"PUT\", \"DELETE\"],\n \"subjects\": [\"group:admins\"],\n \"policy\": \"two_factor\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/policies/:policy_id", + "host": ["{{base_url}}"], + "path": ["api", "policies", ":policy_id"], + "variable": [ + { + "key": "policy_id", + "value": "pol_93f8s2", + "description": "Policy ID to update" + } + ] + }, + "description": "Fully replace an existing policy rule. All required fields must be provided.\n\nReturns 404 if policy not found." + }, + "response": [] + }, + { + "name": "Delete Policy", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "url": { + "raw": "{{base_url}}/api/policies/:policy_id", + "host": ["{{base_url}}"], + "path": ["api", "policies", ":policy_id"], + "variable": [ + { + "key": "policy_id", + "value": "pol_93f8s2", + "description": "Policy ID to delete" + } + ] + }, + "description": "Delete a policy by its ID.\n\nReturns 404 if policy not found." + }, + "response": [] + }, + { + "name": "Verify Policy (Dry-run)", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"domain\": \"secure.example.com\",\n \"path\": \"/admin/dashboard\",\n \"method\": \"POST\",\n \"username\": \"test.user1\",\n \"groups\": [\"developers\", \"admins\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/policies/verify", + "host": ["{{base_url}}"], + "path": ["api", "policies", "verify"] + }, + "description": "Dry-run policy evaluation — simulate a request and see which policy matches.\n\n**Required:** `domain`, `path`\n**Optional:** `method` (defaults to GET), `username`, `groups`\n\nReturns whether a policy matched, and if so the policy ID, name, and required action level." + }, + "response": [] + }, + { + "name": "Get User Policies", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{bearer_token}}" + } + ], + "url": { + "raw": "{{base_url}}/api/users/:username/policies", + "host": ["{{base_url}}"], + "path": ["api", "users", ":username", "policies"], + "variable": [ + { + "key": "username", + "value": "john.doe", + "description": "Username to evaluate policies for" + } + ] + }, + "description": "Get all policies that apply to a specific user. Evaluates both direct username matches (`user:john.doe`) and group membership matches (`group:admins`, `group:users`).\n\nReturns an array of policy matches with match reason (direct or via group).\n\nReturns 404 if user not found." }, "response": [] } @@ -122,7 +348,7 @@ "script": { "type": "text/javascript", "exec": [ - "// Pre-request script can be used to set dynamic variables", + "// Pre-request script — set dynamic variables here if needed", "console.log('Request:', pm.request);" ] } @@ -132,12 +358,12 @@ "script": { "type": "text/javascript", "exec": [ - "// Test script to validate responses", - "pm.test('Status code is 200 or 201', function () {", + "// Shared test scripts", + "pm.test('Status code is 2xx', function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 204]);", "});", "", - "// For health check, ensure status is ok", + "// Health check assertions", "if (pm.request.url.toString().includes('/health')) {", " pm.test('Health check returns ok', function () {", " var jsonData = pm.response.json();", @@ -145,17 +371,25 @@ " });", "}", "", - "// For bulk create, check response structure", - "if (pm.request.url.toString().includes('/bulk')) {", - " pm.test('Bulk create returns success field', function () {", + "// Bulk create assertions", + "if (pm.request.url.toString().includes('/users/bulk')) {", + " pm.test('Bulk create has expected fields', function () {", " var jsonData = pm.response.json();", " pm.expect(jsonData).to.have.property('success');", " pm.expect(jsonData).to.have.property('created');", " pm.expect(jsonData).to.have.property('users');", " });", + "}", + "", + "// Policy verify assertions", + "if (pm.request.url.toString().includes('/policies/verify')) {", + " pm.test('Verify response has matched field', function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('matched');", + " });", "}" ] } } ] -} \ No newline at end of file +}