Authentication
Authentication endpoints for agents to login, verify tokens, refresh sessions, and recover forgotten passwords.
All endpoints in this section are public — no authentication required (except /auth/verify which validates a token).
Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /auth/login | Authenticate agent and get JWT |
POST | /auth/verify | Verify agent JWT token |
POST | /auth/refresh | Refresh access token |
POST | /auth/check-username | Check username and get masked email |
POST | /auth/forgot-password | Request a password reset email |
POST | /auth/reset-password | Reset password using a token from email |
Agent Login
POST /auth/login
Authenticates an agent using their username and password. On successful authentication, returns an access token (JWT), refresh token, and basic agent info.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
username | string | ✅ | Agent username (3–30 characters) |
password | string | ✅ | Agent password (6–50 characters) |
device_id | string | ✅ | Unique device identifier (IDFV on iOS, Android ID, or UUID for web) |
Request
curl -X POST "https://{workspace_id}.firetell.app/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{
"username": "agent_john",
"password": "secretpassword",
"device_id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890"
}'
Response 200 OK
{
"tokens": {
"access_token": "eyJhbGciOiJIUzI1NiIsIn...",
"expires_at": 1783935600000,
"refresh_token": "eyJhbGciOiJIUzI1NiIsIn..."
},
"info": {
"username": "agent_john",
"domain": "yourcompany.firetell.app",
"display_name": "John Doe"
}
}
Error Responses
| Status | Description |
|---|---|
400 | workspace_id not found or validation error |
401 | Invalid credentials or agent account is inactive |
Verify Agent JWT
POST /auth/verify
Verifies a previously generated JWT token and returns information about the token's subject (the authenticated agent or client).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
token | string | ✅ | The JWT token to verify |
Request
curl -X POST "https://{workspace_id}.firetell.app/api/v1/auth/verify" \
-H "Content-Type: application/json" \
-d '{
"token": "eyJhbGciOiJIUzI1NiIsIn..."
}'
Response 200 OK
{
"username": "agent_john",
"domain": "yourcompany.firetell.app",
"workspace_id": "ws_123456",
"display_name": "John Doe",
"avatar": "https://storage.firetell.app/avatars/ag_123.jpg",
"expires_at": 1783935600000
}
Error Responses
| Status | Description |
|---|---|
401 | Missing token or invalid token signature |
Refresh Token
POST /auth/refresh
Exchange a valid refresh token for a new access token and refresh token pair. This implements token rotation — each refresh token can only be used once, and a new pair is issued on every refresh.
Token Lifecycle
| Token | Lifetime | Purpose |
|---|---|---|
access_token | 1 day | Used for API access (Bearer header) |
refresh_token | 30 days | Used only at this endpoint to get new tokens |
Refresh tokens cannot be used as Bearer tokens for API access. The server will reject them with 401 Unauthorized.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
refresh_token | string | ✅ | The refresh token from login/refresh |
device_id | string | ✅ | Same device ID used during login |
Request
curl -X POST "https://{workspace_id}.firetell.app/api/v1/auth/refresh" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIsIn...",
"device_id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890"
}'
Response 200 OK
{
"access_token": "eyJhbGciOiJIUzI1NiIsIn...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsIn...",
"expires_at": 1784022000000
}
After refreshing, the previous refresh token is no longer valid. Always store and use the new refresh_token from the response. Reusing an old refresh token will be rejected as a potential token theft.
Error Responses
| Status | Description |
|---|---|
401 | Invalid, expired, or wrong type of token |
401 | Refresh token has been revoked or already used |
401 | Agent not found or inactive |
400 | Missing workspace_id |
Check Username
POST /auth/check-username
Check whether an agent username exists in the workspace and return the agent's masked email address. This helps agents who remember their username but have forgotten which email address is associated with their account.
This endpoint is public — no authentication required.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
username | string | ✅ | Agent username (3–30 characters) |
Request
curl -X POST "https://{workspace_id}.firetell.app/api/v1/auth/check-username" \
-H "Content-Type: application/json" \
-d '{
"username": "agent_john"
}'
Response 200 OK
{
"email": "ag*********@gmail.com"
}
The email address is masked to protect privacy — only the first two characters of the local part are visible, and the domain remains intact.
| Original email | Masked email |
|---|---|
your.agentemail@gmail.com | yo*********@gmail.com |
ab@company.com | a*@company.com |
a@example.com | *@example.com |
Error Responses
| Status | Description |
|---|---|
400 | workspace_id not found or validation error |
404 | Agent not found or no email address configured |
Forgot Password
POST /auth/forgot-password
Request a password reset email. If the username and email combination matches an active agent in the workspace, a reset email is sent with a link that expires in 30 minutes.
This endpoint is public — no authentication required.
:::tip Security This endpoint always returns the same success message regardless of whether the agent exists or the email matches. This prevents attackers from enumerating valid accounts. :::
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
username | string | ✅ | Agent username (3–30 characters) |
email | string | ✅ | Agent's email address |
Request
curl -X POST "https://{workspace_id}.firetell.app/api/v1/auth/forgot-password" \
-H "Content-Type: application/json" \
-d '{
"username": "agent_john",
"email": "john@company.com"
}'
Response 200 OK
{
"message": "If the account exists, a reset email has been sent."
}
Reset Email
If the credentials match, the agent receives an email from Firetell • Workspace Name with:
- Workspace name and portal URL
- A "Reset Password" button linking to
https://{workspace_id}.firetell.app/auth/reset-password?token={JWT} - The link expires in 30 minutes
Error Responses
| Status | Description |
|---|---|
400 | workspace_id not found or validation error |
Reset Password
POST /auth/reset-password
Reset an agent's password using the token received via the password reset email. The token is a JWT signed by the server with a 30-minute expiry.
This endpoint is public — no authentication required. The reset token itself serves as proof of identity.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
token | string | ✅ | Reset token from the email link |
new_password | string | ✅ | New password (6–50 characters) |
Request
curl -X POST "https://{workspace_id}.firetell.app/api/v1/auth/reset-password" \
-H "Content-Type: application/json" \
-d '{
"token": "eyJhbGciOiJIUzI1NiIsIn...",
"new_password": "myNewSecurePassword123"
}'
Response 200 OK
{
"message": "Password has been reset successfully."
}
Error Responses
| Status | Description |
|---|---|
400 | Invalid or expired reset token |
400 | Agent not found or has been deleted |
500 | Password reset is not configured on the server |
Password Reset Flow
The complete password reset flow involves three steps:
1. Agent calls POST /auth/check-username
→ Receives masked email (e.g. "ag*****@gmail.com")
→ Now knows which email to use
2. Agent calls POST /auth/forgot-password with username + email
→ Server sends reset email to the agent's address
→ Agent clicks "Reset Password" link in email
3. Client extracts token from URL query parameter
→ Calls POST /auth/reset-password with token + new password
→ Password is updated, agent can log in with new credentials
Reset tokens are single-purpose JWT tokens — they can only be used to reset a password and cannot be used as access tokens for other API calls.