mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-26 01:58:21 +03:00
update auth api endpoint descriptions and docs
This commit is contained in:
parent
1f60c64a5e
commit
743acd87fd
@ -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`.
|
1. Log in as an **admin** user via port `8971`.
|
||||||
2. Navigate to **Settings > Users**.
|
2. Navigate to **Settings > Users**.
|
||||||
3. Edit a user’s role by selecting **admin** or **viewer**.
|
3. Edit a user’s 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
|
||||||
|
|||||||
105
docs/static/frigate-api.yaml
vendored
105
docs/static/frigate-api.yaml
vendored
@ -14,7 +14,11 @@ paths:
|
|||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: auth_auth_get
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
@ -22,11 +26,21 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
schema: {}
|
||||||
|
"202":
|
||||||
|
description: Authentication Accepted
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {}
|
||||||
|
"401":
|
||||||
|
description: Authentication Failed
|
||||||
/profile:
|
/profile:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: profile_profile_get
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
@ -34,11 +48,16 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
schema: {}
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
/logout:
|
/logout:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: logout_logout_get
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
@ -46,11 +65,22 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
schema: {}
|
||||||
|
"303":
|
||||||
|
description: See Other (redirects to login page)
|
||||||
/login:
|
/login:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: login_login_post
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@ -64,6 +94,11 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
schema: {}
|
||||||
|
"401":
|
||||||
|
description: Login Failed - Invalid credentials
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {}
|
||||||
"422":
|
"422":
|
||||||
description: Validation Error
|
description: Validation Error
|
||||||
content:
|
content:
|
||||||
@ -74,7 +109,10 @@ paths:
|
|||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: get_users_users_get
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
@ -82,10 +120,19 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
schema: {}
|
||||||
|
"403":
|
||||||
|
description: Forbidden - Admin role required
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: create_user_users_post
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@ -99,6 +146,13 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
schema: {}
|
||||||
|
"400":
|
||||||
|
description: Bad Request - Invalid username or role
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {}
|
||||||
|
"403":
|
||||||
|
description: Forbidden - Admin role required
|
||||||
"422":
|
"422":
|
||||||
description: Validation Error
|
description: Validation Error
|
||||||
content:
|
content:
|
||||||
@ -109,7 +163,10 @@ paths:
|
|||||||
delete:
|
delete:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: delete_user_users__username__delete
|
||||||
parameters:
|
parameters:
|
||||||
- name: username
|
- name: username
|
||||||
@ -118,12 +175,15 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
title: Username
|
title: Username
|
||||||
|
description: The username of the user to delete
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Successful Response
|
description: Successful Response
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
schema: {}
|
||||||
|
"403":
|
||||||
|
description: Forbidden - Cannot delete admin user or admin role required
|
||||||
"422":
|
"422":
|
||||||
description: Validation Error
|
description: Validation Error
|
||||||
content:
|
content:
|
||||||
@ -134,7 +194,17 @@ paths:
|
|||||||
put:
|
put:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: update_password_users__username__password_put
|
||||||
parameters:
|
parameters:
|
||||||
- name: username
|
- name: username
|
||||||
@ -143,6 +213,7 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
title: Username
|
title: Username
|
||||||
|
description: The username of the user whose password to update
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -155,6 +226,14 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
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":
|
"422":
|
||||||
description: Validation Error
|
description: Validation Error
|
||||||
content:
|
content:
|
||||||
@ -165,7 +244,10 @@ paths:
|
|||||||
put:
|
put:
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- 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
|
operationId: update_role_users__username__role_put
|
||||||
parameters:
|
parameters:
|
||||||
- name: username
|
- name: username
|
||||||
@ -174,6 +256,7 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
title: Username
|
title: Username
|
||||||
|
description: The username of the user whose role to update
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -186,6 +269,10 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema: {}
|
schema: {}
|
||||||
|
"400":
|
||||||
|
description: Bad Request - Invalid role
|
||||||
|
"403":
|
||||||
|
description: Forbidden - Cannot modify admin user's role or admin role required
|
||||||
"422":
|
"422":
|
||||||
description: Validation Error
|
description: Validation Error
|
||||||
content:
|
content:
|
||||||
|
|||||||
@ -549,7 +549,12 @@ def resolve_role(
|
|||||||
|
|
||||||
|
|
||||||
# Endpoints
|
# 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):
|
def auth(request: Request):
|
||||||
auth_config: AuthConfig = request.app.frigate_config.auth
|
auth_config: AuthConfig = request.app.frigate_config.auth
|
||||||
proxy_config: ProxyConfig = request.app.frigate_config.proxy
|
proxy_config: ProxyConfig = request.app.frigate_config.proxy
|
||||||
@ -689,7 +694,12 @@ def auth(request: Request):
|
|||||||
return fail_response
|
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):
|
def profile(request: Request):
|
||||||
username = request.headers.get("remote-user", "anonymous")
|
username = request.headers.get("remote-user", "anonymous")
|
||||||
role = request.headers.get("remote-role", "viewer")
|
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):
|
def logout(request: Request):
|
||||||
auth_config: AuthConfig = request.app.frigate_config.auth
|
auth_config: AuthConfig = request.app.frigate_config.auth
|
||||||
response = RedirectResponse("/login", status_code=303)
|
response = RedirectResponse("/login", status_code=303)
|
||||||
@ -714,7 +729,12 @@ def logout(request: Request):
|
|||||||
limiter = Limiter(key_func=get_remote_addr)
|
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)
|
@limiter.limit(limit_value=rateLimiter.get_limit)
|
||||||
def login(request: Request, body: AppPostLoginBody):
|
def login(request: Request, body: AppPostLoginBody):
|
||||||
JWT_COOKIE_NAME = request.app.frigate_config.auth.cookie_name
|
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)
|
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():
|
def get_users():
|
||||||
exports = (
|
exports = (
|
||||||
User.select(User.username, User.role).order_by(User.username).dicts().iterator()
|
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])
|
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(
|
def create_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
body: AppPostUsersBody,
|
body: AppPostUsersBody,
|
||||||
@ -789,7 +819,12 @@ def create_user(
|
|||||||
return JSONResponse(content={"username": body.username})
|
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):
|
def delete_user(request: Request, username: str):
|
||||||
# Prevent deletion of the built-in admin user
|
# Prevent deletion of the built-in admin user
|
||||||
if username == "admin":
|
if username == "admin":
|
||||||
@ -802,7 +837,10 @@ def delete_user(request: Request, username: str):
|
|||||||
|
|
||||||
|
|
||||||
@router.put(
|
@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(
|
async def update_password(
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -887,6 +925,8 @@ async def update_password(
|
|||||||
@router.put(
|
@router.put(
|
||||||
"/users/{username}/role",
|
"/users/{username}/role",
|
||||||
dependencies=[Depends(require_role(["admin"]))],
|
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(
|
async def update_role(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user