update auth api endpoint descriptions and docs

This commit is contained in:
Josh Hawkins 2025-12-14 12:35:55 -06:00
parent 1f60c64a5e
commit 743acd87fd
3 changed files with 183 additions and 17 deletions

View File

@ -270,3 +270,42 @@ To use role-based access control, you must connect to Frigate via the **authenti
1. Log in as an **admin** user via port `8971`.
2. Navigate to **Settings > Users**.
3. Edit a users role by selecting **admin** or **viewer**.
## API Authentication Guide
## Getting a Bearer Token
To use the Frigate API, you need to authenticate first. Follow these steps to obtain a Bearer token:
### 1. Login
Make a POST request to `/login` with your credentials:
```bash
curl -i -X POST https://frigate_ip:8971/api/login \
-H "Content-Type: application/json" \
-d '{"user": "admin", "password": "your_password"}'
```
::: note
You may need to include `-k` in the argument list in these steps (eg: `curl -k -i -X POST ...`) if your Frigate instance is using a self-signed certificate.
:::
The response will contain a cookie with the JWT token.
### 2. Using the Bearer Token
Once you have the token, include it in the Authorization header for subsequent requests:
```bash
curl -H "Authorization: Bearer <your_token>" https://frigate_ip:8971/api/profile
```
### 3. Token Lifecycle
- Tokens are valid for the configured session length
- Tokens are automatically refreshed when you visit the `/auth` endpoint
- Tokens are invalidated when the user's password is changed
- Use `/logout` to clear your session cookie

View File

@ -14,7 +14,11 @@ paths:
get:
tags:
- Auth
summary: Auth
summary: Authenticate request
description: |-
Authenticates the current request based on proxy headers or JWT token.
Returns user role and permissions for camera access.
This endpoint verifies authentication credentials and manages JWT token refresh.
operationId: auth_auth_get
responses:
"200":
@ -22,11 +26,21 @@ paths:
content:
application/json:
schema: {}
"202":
description: Authentication Accepted
content:
application/json:
schema: {}
"401":
description: Authentication Failed
/profile:
get:
tags:
- Auth
summary: Profile
summary: Get user profile
description: |-
Returns the current authenticated user's profile including username, role, and allowed cameras.
This endpoint requires authentication and returns information about the user's permissions.
operationId: profile_profile_get
responses:
"200":
@ -34,11 +48,16 @@ paths:
content:
application/json:
schema: {}
"401":
description: Unauthorized
/logout:
get:
tags:
- Auth
summary: Logout
summary: Logout user
description: |-
Logs out the current user by clearing the session cookie.
After logout, subsequent requests will require re-authentication.
operationId: logout_logout_get
responses:
"200":
@ -46,11 +65,22 @@ paths:
content:
application/json:
schema: {}
"303":
description: See Other (redirects to login page)
/login:
post:
tags:
- Auth
summary: Login
summary: Login with credentials
description: |-
Authenticates a user with username and password.
Returns a JWT token as a secure HTTP-only cookie that can be used for subsequent API requests.
The JWT token can also be retrieved from the response and used as a Bearer token in the Authorization header.
Example using Bearer token:
```
curl -H "Authorization: Bearer <token_value>" https://frigate_ip:8971/api/profile
```
operationId: login_login_post
requestBody:
required: true
@ -64,6 +94,11 @@ paths:
content:
application/json:
schema: {}
"401":
description: Login Failed - Invalid credentials
content:
application/json:
schema: {}
"422":
description: Validation Error
content:
@ -74,7 +109,10 @@ paths:
get:
tags:
- Auth
summary: Get Users
summary: Get all users
description: |-
Returns a list of all users with their usernames and roles.
Requires admin role. Each user object contains the username and assigned role.
operationId: get_users_users_get
responses:
"200":
@ -82,10 +120,19 @@ paths:
content:
application/json:
schema: {}
"403":
description: Forbidden - Admin role required
post:
tags:
- Auth
summary: Create User
summary: Create new user
description: |-
Creates a new user with the specified username, password, and role.
Requires admin role. Password must meet strength requirements:
- Minimum 8 characters
- At least one uppercase letter
- At least one digit
- At least one special character (!@#$%^&*(),.?":{}\|<>)
operationId: create_user_users_post
requestBody:
required: true
@ -99,6 +146,13 @@ paths:
content:
application/json:
schema: {}
"400":
description: Bad Request - Invalid username or role
content:
application/json:
schema: {}
"403":
description: Forbidden - Admin role required
"422":
description: Validation Error
content:
@ -109,7 +163,10 @@ paths:
delete:
tags:
- Auth
summary: Delete User
summary: Delete user
description: |-
Deletes a user by username. The built-in admin user cannot be deleted.
Requires admin role. Returns success message or error if user not found.
operationId: delete_user_users__username__delete
parameters:
- name: username
@ -118,12 +175,15 @@ paths:
schema:
type: string
title: Username
description: The username of the user to delete
responses:
"200":
description: Successful Response
content:
application/json:
schema: {}
"403":
description: Forbidden - Cannot delete admin user or admin role required
"422":
description: Validation Error
content:
@ -134,7 +194,17 @@ paths:
put:
tags:
- Auth
summary: Update Password
summary: Update user password
description: |-
Updates a user's password. Users can only change their own password unless they have admin role.
Requires the current password to verify identity for non-admin users.
Password must meet strength requirements:
- Minimum 8 characters
- At least one uppercase letter
- At least one digit
- At least one special character (!@#$%^&*(),.?":{}\|<>)
If user changes their own password, a new JWT cookie is automatically issued.
operationId: update_password_users__username__password_put
parameters:
- name: username
@ -143,6 +213,7 @@ paths:
schema:
type: string
title: Username
description: The username of the user whose password to update
requestBody:
required: true
content:
@ -155,6 +226,14 @@ paths:
content:
application/json:
schema: {}
"400":
description: Bad Request - Current password required or password doesn't meet requirements
"401":
description: Unauthorized - Current password is incorrect
"403":
description: Forbidden - Viewers can only update their own password
"404":
description: Not Found - User not found
"422":
description: Validation Error
content:
@ -165,7 +244,10 @@ paths:
put:
tags:
- Auth
summary: Update Role
summary: Update user role
description: |-
Updates a user's role. The built-in admin user's role cannot be modified.
Requires admin role. Valid roles are defined in the configuration.
operationId: update_role_users__username__role_put
parameters:
- name: username
@ -174,6 +256,7 @@ paths:
schema:
type: string
title: Username
description: The username of the user whose role to update
requestBody:
required: true
content:
@ -186,6 +269,10 @@ paths:
content:
application/json:
schema: {}
"400":
description: Bad Request - Invalid role
"403":
description: Forbidden - Cannot modify admin user's role or admin role required
"422":
description: Validation Error
content:

View File

@ -549,7 +549,12 @@ def resolve_role(
# Endpoints
@router.get("/auth", dependencies=[Depends(allow_public())])
@router.get(
"/auth",
dependencies=[Depends(allow_public())],
summary="Authenticate request",
description="Authenticates the current request based on proxy headers or JWT token. Returns user role and permissions for camera access.",
)
def auth(request: Request):
auth_config: AuthConfig = request.app.frigate_config.auth
proxy_config: ProxyConfig = request.app.frigate_config.proxy
@ -689,7 +694,12 @@ def auth(request: Request):
return fail_response
@router.get("/profile", dependencies=[Depends(allow_any_authenticated())])
@router.get(
"/profile",
dependencies=[Depends(allow_any_authenticated())],
summary="Get user profile",
description="Returns the current authenticated user's profile including username, role, and allowed cameras.",
)
def profile(request: Request):
username = request.headers.get("remote-user", "anonymous")
role = request.headers.get("remote-role", "viewer")
@ -703,7 +713,12 @@ def profile(request: Request):
)
@router.get("/logout", dependencies=[Depends(allow_public())])
@router.get(
"/logout",
dependencies=[Depends(allow_public())],
summary="Logout user",
description="Logs out the current user by clearing the session cookie.",
)
def logout(request: Request):
auth_config: AuthConfig = request.app.frigate_config.auth
response = RedirectResponse("/login", status_code=303)
@ -714,7 +729,12 @@ def logout(request: Request):
limiter = Limiter(key_func=get_remote_addr)
@router.post("/login", dependencies=[Depends(allow_public())])
@router.post(
"/login",
dependencies=[Depends(allow_public())],
summary="Login with credentials",
description="Authenticates a user with username and password. Returns a JWT token as a secure HTTP-only cookie that can be used for subsequent API requests. The token can also be retrieved and used as a Bearer token in the Authorization header.",
)
@limiter.limit(limit_value=rateLimiter.get_limit)
def login(request: Request, body: AppPostLoginBody):
JWT_COOKIE_NAME = request.app.frigate_config.auth.cookie_name
@ -752,7 +772,12 @@ def login(request: Request, body: AppPostLoginBody):
return JSONResponse(content={"message": "Login failed"}, status_code=401)
@router.get("/users", dependencies=[Depends(require_role(["admin"]))])
@router.get(
"/users",
dependencies=[Depends(require_role(["admin"]))],
summary="Get all users",
description="Returns a list of all users with their usernames and roles. Requires admin role.",
)
def get_users():
exports = (
User.select(User.username, User.role).order_by(User.username).dicts().iterator()
@ -760,7 +785,12 @@ def get_users():
return JSONResponse([e for e in exports])
@router.post("/users", dependencies=[Depends(require_role(["admin"]))])
@router.post(
"/users",
dependencies=[Depends(require_role(["admin"]))],
summary="Create new user",
description="Creates a new user with the specified username, password, and role. Requires admin role. Password must meet strength requirements.",
)
def create_user(
request: Request,
body: AppPostUsersBody,
@ -789,7 +819,12 @@ def create_user(
return JSONResponse(content={"username": body.username})
@router.delete("/users/{username}", dependencies=[Depends(require_role(["admin"]))])
@router.delete(
"/users/{username}",
dependencies=[Depends(require_role(["admin"]))],
summary="Delete user",
description="Deletes a user by username. The built-in admin user cannot be deleted. Requires admin role.",
)
def delete_user(request: Request, username: str):
# Prevent deletion of the built-in admin user
if username == "admin":
@ -802,7 +837,10 @@ def delete_user(request: Request, username: str):
@router.put(
"/users/{username}/password", dependencies=[Depends(allow_any_authenticated())]
"/users/{username}/password",
dependencies=[Depends(allow_any_authenticated())],
summary="Update user password",
description="Updates a user's password. Users can only change their own password unless they have admin role. Requires the current password to verify identity. Password must meet strength requirements (minimum 8 characters, uppercase letter, digit, and special character).",
)
async def update_password(
request: Request,
@ -887,6 +925,8 @@ async def update_password(
@router.put(
"/users/{username}/role",
dependencies=[Depends(require_role(["admin"]))],
summary="Update user role",
description="Updates a user's role. The built-in admin user's role cannot be modified. Requires admin role.",
)
async def update_role(
request: Request,