M2-T02: add session/auth JSON API for the SPA
- GET /api/session (user + csrf_token, 401 when unauthenticated) - POST /api/auth/login (sets HttpOnly session cookie; 401 on bad creds; no CSRF) - POST /api/auth/logout (session+CSRF; revokes session, clears cookie; 204) - POST /api/auth/password (session+CSRF; reuses change_password; 400 on failure; 204) - reuses app/services/auth.py and shared require_session/require_csrf deps - register router in app/main.py; regenerate openapi/ - tests/test_api_session.py
This commit is contained in:
@@ -350,6 +350,176 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"api-session"
|
||||
],
|
||||
"summary": "Get Session",
|
||||
"description": "Return the current session user and CSRF token. Returns 401 if not authenticated.",
|
||||
"operationId": "get_session_api_session_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"api-session"
|
||||
],
|
||||
"summary": "Post Login",
|
||||
"description": "Authenticate with username and password.\n\nOn success, sets an HttpOnly session cookie and returns the session user + CSRF token.\nOn failure, returns 401 with no cookie set.\nNo X-CSRF-Token required (unauthenticated endpoint).",
|
||||
"operationId": "post_login_api_auth_login_post",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/LoginRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/logout": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"api-session"
|
||||
],
|
||||
"summary": "Post Logout",
|
||||
"description": "Revoke the current session and clear the session cookie.\nRequires authentication and X-CSRF-Token header.\nReturns 204 No Content.",
|
||||
"operationId": "post_logout_api_auth_logout_post",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "X-CSRF-Token",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "X-Csrf-Token"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/password": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"api-session"
|
||||
],
|
||||
"summary": "Post Change Password",
|
||||
"description": "Change the current user's password.\nRequires authentication and X-CSRF-Token header.\nOn AuthPasswordChangeError returns 400 with a generic message.\nOn success, force_password_change becomes False (handled by the service).\nReturns 204 No Content.",
|
||||
"operationId": "post_change_password_api_auth_password_post",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "X-CSRF-Token",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "X-Csrf-Token"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PasswordChangeRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/homeassistant/publish": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -673,6 +843,47 @@
|
||||
"type": "object",
|
||||
"title": "HTTPValidationError"
|
||||
},
|
||||
"LoginRequest": {
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string",
|
||||
"title": "Username"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"title": "Password"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"username",
|
||||
"password"
|
||||
],
|
||||
"title": "LoginRequest"
|
||||
},
|
||||
"PasswordChangeRequest": {
|
||||
"properties": {
|
||||
"current_password": {
|
||||
"type": "string",
|
||||
"title": "Current Password"
|
||||
},
|
||||
"new_password": {
|
||||
"type": "string",
|
||||
"title": "New Password"
|
||||
},
|
||||
"confirm_password": {
|
||||
"type": "string",
|
||||
"title": "Confirm Password"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"current_password",
|
||||
"new_password",
|
||||
"confirm_password"
|
||||
],
|
||||
"title": "PasswordChangeRequest"
|
||||
},
|
||||
"PublicIPCheckResponse": {
|
||||
"properties": {
|
||||
"status": {
|
||||
@@ -703,6 +914,41 @@
|
||||
],
|
||||
"title": "PublicIPCheckResponse"
|
||||
},
|
||||
"SessionResponse": {
|
||||
"properties": {
|
||||
"user": {
|
||||
"$ref": "#/components/schemas/SessionUser"
|
||||
},
|
||||
"csrf_token": {
|
||||
"type": "string",
|
||||
"title": "Csrf Token"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"user",
|
||||
"csrf_token"
|
||||
],
|
||||
"title": "SessionResponse"
|
||||
},
|
||||
"SessionUser": {
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string",
|
||||
"title": "Username"
|
||||
},
|
||||
"force_password_change": {
|
||||
"type": "boolean",
|
||||
"title": "Force Password Change"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"username",
|
||||
"force_password_change"
|
||||
],
|
||||
"title": "SessionUser"
|
||||
},
|
||||
"StatusResponse": {
|
||||
"properties": {
|
||||
"status": {
|
||||
|
||||
@@ -222,6 +222,129 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
/api/session:
|
||||
get:
|
||||
tags:
|
||||
- api-session
|
||||
summary: Get Session
|
||||
description: Return the current session user and CSRF token. Returns 401 if
|
||||
not authenticated.
|
||||
operationId: get_session_api_session_get
|
||||
responses:
|
||||
'200':
|
||||
description: Successful Response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SessionResponse'
|
||||
/api/auth/login:
|
||||
post:
|
||||
tags:
|
||||
- api-session
|
||||
summary: Post Login
|
||||
description: 'Authenticate with username and password.
|
||||
|
||||
|
||||
On success, sets an HttpOnly session cookie and returns the session user +
|
||||
CSRF token.
|
||||
|
||||
On failure, returns 401 with no cookie set.
|
||||
|
||||
No X-CSRF-Token required (unauthenticated endpoint).'
|
||||
operationId: post_login_api_auth_login_post
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LoginRequest'
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: Successful Response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SessionResponse'
|
||||
'422':
|
||||
description: Validation Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
/api/auth/logout:
|
||||
post:
|
||||
tags:
|
||||
- api-session
|
||||
summary: Post Logout
|
||||
description: 'Revoke the current session and clear the session cookie.
|
||||
|
||||
Requires authentication and X-CSRF-Token header.
|
||||
|
||||
Returns 204 No Content.'
|
||||
operationId: post_logout_api_auth_logout_post
|
||||
parameters:
|
||||
- name: X-CSRF-Token
|
||||
in: header
|
||||
required: false
|
||||
schema:
|
||||
anyOf:
|
||||
- type: string
|
||||
- type: 'null'
|
||||
title: X-Csrf-Token
|
||||
responses:
|
||||
'200':
|
||||
description: Successful Response
|
||||
content:
|
||||
application/json:
|
||||
schema: {}
|
||||
'422':
|
||||
description: Validation Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
/api/auth/password:
|
||||
post:
|
||||
tags:
|
||||
- api-session
|
||||
summary: Post Change Password
|
||||
description: 'Change the current user''s password.
|
||||
|
||||
Requires authentication and X-CSRF-Token header.
|
||||
|
||||
On AuthPasswordChangeError returns 400 with a generic message.
|
||||
|
||||
On success, force_password_change becomes False (handled by the service).
|
||||
|
||||
Returns 204 No Content.'
|
||||
operationId: post_change_password_api_auth_password_post
|
||||
parameters:
|
||||
- name: X-CSRF-Token
|
||||
in: header
|
||||
required: false
|
||||
schema:
|
||||
anyOf:
|
||||
- type: string
|
||||
- type: 'null'
|
||||
title: X-Csrf-Token
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PasswordChangeRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Successful Response
|
||||
content:
|
||||
application/json:
|
||||
schema: {}
|
||||
'422':
|
||||
description: Validation Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
/homeassistant/publish:
|
||||
post:
|
||||
tags:
|
||||
@@ -443,6 +566,36 @@ components:
|
||||
title: Detail
|
||||
type: object
|
||||
title: HTTPValidationError
|
||||
LoginRequest:
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
title: Username
|
||||
password:
|
||||
type: string
|
||||
title: Password
|
||||
type: object
|
||||
required:
|
||||
- username
|
||||
- password
|
||||
title: LoginRequest
|
||||
PasswordChangeRequest:
|
||||
properties:
|
||||
current_password:
|
||||
type: string
|
||||
title: Current Password
|
||||
new_password:
|
||||
type: string
|
||||
title: New Password
|
||||
confirm_password:
|
||||
type: string
|
||||
title: Confirm Password
|
||||
type: object
|
||||
required:
|
||||
- current_password
|
||||
- new_password
|
||||
- confirm_password
|
||||
title: PasswordChangeRequest
|
||||
PublicIPCheckResponse:
|
||||
properties:
|
||||
status:
|
||||
@@ -466,6 +619,31 @@ components:
|
||||
- checked_at
|
||||
- changed
|
||||
title: PublicIPCheckResponse
|
||||
SessionResponse:
|
||||
properties:
|
||||
user:
|
||||
$ref: '#/components/schemas/SessionUser'
|
||||
csrf_token:
|
||||
type: string
|
||||
title: Csrf Token
|
||||
type: object
|
||||
required:
|
||||
- user
|
||||
- csrf_token
|
||||
title: SessionResponse
|
||||
SessionUser:
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
title: Username
|
||||
force_password_change:
|
||||
type: boolean
|
||||
title: Force Password Change
|
||||
type: object
|
||||
required:
|
||||
- username
|
||||
- force_password_change
|
||||
title: SessionUser
|
||||
StatusResponse:
|
||||
properties:
|
||||
status:
|
||||
|
||||
Reference in New Issue
Block a user