Authenticate with AI Smart Redact
The Orchestrator API uses JWT bearer tokens for authentication. This guide covers the authentication flow, first log-in setup, API key authentication for automated workflows, and command-line examples.
Overview
Two tokens are involved in the authentication flow:
| Token | Lifetime | Purpose |
|---|---|---|
| Access token | 15 minutes | Short-lived JWT sent as Authorization: Bearer <TOKEN> on every request. |
| Refresh token | 30 days | Long-lived opaque token stored as an HttpOnly cookie scoped to /v1/auth. Used to obtain new access tokens without re-entering credentials. |
All endpoints require an access token except POST /v1/auth/login and POST /v1/auth/refresh.
The refresh token cookie is scoped to /v1/auth. The browser only sends this cookie on requests to /v1/auth/* paths (such as /v1/auth/refresh). It isn’t sent on other API paths like /v1/users. If your refresh request isn’t including the cookie, verify the request URL starts with /v1/auth.
Default credentials
A seeded admin account is created automatically on first startup:
| Field | Value |
|---|---|
admin@example.com | |
| Password | Admin@1234!Tmp |
The account has the PasswordResetRequired flag set. Change this password immediately after the first log in.
First log-in flow
- Call
POST /v1/auth/loginwith the default credentials. - The response contains an access token with a
password_reset_requiredclaim. - Call
POST /v1/auth/reset-passwordwith the token from step 2 to set a new password. - Use the new access token returned by step 3 for all subsequent requests.
The password reset isn’t enforced. You can use other endpoints without resetting first. However, changing the default password immediately is strongly recommended.
JWT configuration
Setting used (Orchestrator): Jwt.SecretKey. Generate the value with the command below.
The Orchestrator signs JWT tokens with an HMAC-SHA256 secret key. Generate one and set it before starting the Orchestrator:
openssl rand -base64 64 | tr -d '\n'
environment:
Jwt__SecretKey: "<JWT_SECRET_KEY>"
For the full settings catalog (SecretKey, ExpirationMinutes, RefreshTokenExpirationDays), refer to Orchestrator > JWT.
Command-line usage
The following examples use curl. Save the Orchestrator base URL to a variable:
BASE_URL=http://localhost:9983
Log in
curl -s -c cookies.txt -X POST "$BASE_URL/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"login": "admin@example.com", "password": "Admin@1234!Tmp"}' | tee login_response.json
Extract the token:
TOKEN=$(grep -o '"token":"[^"]*"' login_response.json | cut -d'"' -f4)
Reset password (first log in)
curl -s -c cookies.txt -b cookies.txt -X POST "$BASE_URL/v1/auth/reset-password" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"newPassword": "MySecurePassword1!"}' | tee reset_response.json
TOKEN=$(grep -o '"token":"[^"]*"' reset_response.json | cut -d'"' -f4)
Call a protected endpoint
curl -s -X GET "$BASE_URL/v1/users" \
-H "Authorization: Bearer $TOKEN"
Refresh the access token
When the access token expires, use the saved cookie to refresh it:
curl -s -c cookies.txt -b cookies.txt -X POST "$BASE_URL/v1/auth/refresh" | tee refresh_response.json
TOKEN=$(grep -o '"token":"[^"]*"' refresh_response.json | cut -d'"' -f4)
The refresh token is automatically rotated. The cookie file is updated with the new value.
Change password
curl -s -X POST "$BASE_URL/v1/auth/change-password" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"currentPassword": "OldPassword1!", "newPassword": "NewPassword1!"}'
All existing refresh tokens are revoked and a new access token is returned.
Log out
curl -s -b cookies.txt -X POST "$BASE_URL/v1/auth/logout" \
-H "Authorization: Bearer $TOKEN"
API key authentication
API keys provide non-interactive authentication for automated scripts and integrations. Unlike JWT, API keys don’t require a log-in flow. Send the key directly in a request header.
How API keys work
- An admin creates an API key for a specific user through
POST /v1/api-keys. - The raw key (for example,
pdft_AbCdEf...) is returned once in the response. It can’t be retrieved later. - Include the key in every request using the
X-Api-Keyheader. - The server hashes the key, looks it up in the database, and authenticates the request as the linked user.
Key details
| Property | Value |
|---|---|
| Format | pdft_ prefix + 32 cryptographically random bytes (base64url, ~48 characters total) |
| Storage | Only the SHA-256 hash is stored in the database |
| Expiration | Required when creating, maximum 12 months |
| Scope | Jobs endpoints only (POST /v1/jobs, GET /v1/jobs, GET /v1/jobs/{id}, POST /v1/jobs/{id}/redaction, GET /v1/jobs/{id}/files/{fileType}) |
Create an API key (admin)
curl -s -X POST "$BASE_URL/v1/api-keys" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "CI Pipeline Key",
"userId": "<USER_ID>",
"expiresAt": "2027-01-01T00:00:00Z"
}'
Replace <USER_ID> with the ID of the user the key authenticates as. Save the raw key field from the response immediately. It won’t be shown again.
Use an API key
# Upload a file
curl -s -X POST "$BASE_URL/v1/jobs" \
-H "X-Api-Key: pdft_your_key_here" \
-F "file=@document.pdf"
# List jobs
curl -s -X GET "$BASE_URL/v1/jobs" \
-H "X-Api-Key: pdft_your_key_here"
# Download redacted file
curl -s -X GET "$BASE_URL/v1/jobs/<JOB_ID>/files/redactedPdf" \
-H "X-Api-Key: pdft_your_key_here" \
--output redacted.pdf
Replace <JOB_ID> with the job identifier returned when the redaction job was created.
Revoke an API key (admin)
curl -s -X POST "$BASE_URL/v1/api-keys/<API_KEY_ID>/revoke" \
-H "Authorization: Bearer $TOKEN"
Replace <API_KEY_ID> with the API key’s ID (returned by GET /v1/api-keys). Revocation is immediate. The key is rejected on the next request.
Swagger UI
The Orchestrator Swagger UI is available at http://localhost:9983/swagger.
To authenticate in Swagger:
- Call
POST /v1/auth/loginto get an access token. - Click the Authorize button (top right).
- In the
Bearer (ApiKey)field, enter:Bearer <TOKEN>(include theBearerprefix). - Click Authorize, then Close.
After resetting or changing your password, re-authorize with the new token returned by the response.
Reset the admin user
If you’re locked out, delete the admin account from the database. It’s re-seeded with the default credentials on the next startup. The seeded admin’s username is admin (separate from the email address).
PostgreSQL (Docker)
docker exec -it smart-redact-orchestrator-db \
psql -U smartredact -d smartredact \
-c "DELETE FROM \"AspNetUsers\" WHERE \"UserName\" = 'admin';"
docker compose restart smart-redact-orchestrator