mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-08 02:27:14 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bc32eb3ca0 |
@@ -88,6 +88,23 @@ Each endpoint accepts **either**:
|
|||||||
1. **User Token** (via `Authorization: Bearer <user_jwt_token>`) - for web UI and authenticated users
|
1. **User Token** (via `Authorization: Bearer <user_jwt_token>`) - for web UI and authenticated users
|
||||||
2. **API Key** (via `X-API-Key` or `Authorization: Bearer <api_key>`) - for external services
|
2. **API Key** (via `X-API-Key` or `Authorization: Bearer <api_key>`) - for external services
|
||||||
|
|
||||||
|
### Inspecting API Key Identity
|
||||||
|
|
||||||
|
`GET /api/v1/system/context` validates an API key (user JWT not accepted) and returns its bound identity without requiring resource permissions:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "ok",
|
||||||
|
"data": {
|
||||||
|
"instance_uuid": "...",
|
||||||
|
"workspace_uuid": "...",
|
||||||
|
"api_key_id": "...",
|
||||||
|
"permissions": ["..."]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Example: Model Management
|
## Example: Model Management
|
||||||
|
|
||||||
### List All LLM Models
|
### List All LLM Models
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ Two kinds of key are accepted:
|
|||||||
Invalid, revoked, or expired keys get `401 Unauthorized`. A valid key whose
|
Invalid, revoked, or expired keys get `401 Unauthorized`. A valid key whose
|
||||||
scopes do not authorize a tool gets `403 Forbidden`.
|
scopes do not authorize a tool gets `403 Forbidden`.
|
||||||
|
|
||||||
|
To inspect key identity and permissions, call `GET /api/v1/system/context` with the API key.
|
||||||
|
|
||||||
## Client configuration
|
## Client configuration
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -15,6 +15,17 @@ from .....workspace.invitation_delivery import InvitationDeliveryService
|
|||||||
@group.group_class('system', '/api/v1/system')
|
@group.group_class('system', '/api/v1/system')
|
||||||
class SystemRouterGroup(group.RouterGroup):
|
class SystemRouterGroup(group.RouterGroup):
|
||||||
async def initialize(self) -> None:
|
async def initialize(self) -> None:
|
||||||
|
@self.route('/context', methods=['GET'], auth_type=group.AuthType.API_KEY)
|
||||||
|
async def _(request_context: RequestContext) -> str:
|
||||||
|
return self.success(
|
||||||
|
data={
|
||||||
|
'instance_uuid': request_context.instance_uuid,
|
||||||
|
'workspace_uuid': request_context.workspace_uuid,
|
||||||
|
'api_key_id': request_context.principal.api_key_uuid,
|
||||||
|
'permissions': sorted(request_context.workspace.permissions),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@self.route('/info', methods=['GET'], auth_type=group.AuthType.NONE)
|
@self.route('/info', methods=['GET'], auth_type=group.AuthType.NONE)
|
||||||
async def _() -> str:
|
async def _() -> str:
|
||||||
# Read wizard_status and wizard_progress from metadata table
|
# Read wizard_status and wizard_progress from metadata table
|
||||||
|
|||||||
@@ -440,6 +440,70 @@ async def test_api_key_secret_is_one_time_and_viewer_cannot_manage_keys(workspac
|
|||||||
assert (await forbidden.get_json())['code'] == 'permission_denied'
|
assert (await forbidden.get_json())['code'] == 'permission_denied'
|
||||||
|
|
||||||
|
|
||||||
|
async def test_api_key_context_returns_bound_identity_without_workspace_permission(workspace_api):
|
||||||
|
application, client, _, owner_token = workspace_api
|
||||||
|
current_response = await client.get('/api/v1/workspaces/current', headers=_auth(owner_token))
|
||||||
|
workspace_uuid = (await current_response.get_json())['data']['workspace']['uuid']
|
||||||
|
|
||||||
|
create_response = await client.post(
|
||||||
|
'/api/v1/apikeys',
|
||||||
|
headers=_auth(owner_token, workspace_uuid),
|
||||||
|
json={'name': 'Context probe', 'scopes': []},
|
||||||
|
)
|
||||||
|
assert create_response.status_code == 200
|
||||||
|
created = (await create_response.get_json())['data']['key']
|
||||||
|
|
||||||
|
missing_auth = await client.get('/api/v1/system/context')
|
||||||
|
assert missing_auth.status_code == 401
|
||||||
|
|
||||||
|
invalid_auth = await client.get(
|
||||||
|
'/api/v1/system/context',
|
||||||
|
headers={'X-API-Key': 'lbk_invalid'},
|
||||||
|
)
|
||||||
|
assert invalid_auth.status_code == 401
|
||||||
|
|
||||||
|
response = await client.get(
|
||||||
|
'/api/v1/system/context',
|
||||||
|
headers={
|
||||||
|
'X-API-Key': created['key'],
|
||||||
|
'X-Workspace-Id': 'caller-selected-workspace-must-be-ignored',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert (await response.get_json())['data'] == {
|
||||||
|
'instance_uuid': application.workspace_service.instance_uuid,
|
||||||
|
'workspace_uuid': workspace_uuid,
|
||||||
|
'api_key_id': created['uuid'],
|
||||||
|
'permissions': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
bearer_response = await client.get(
|
||||||
|
'/api/v1/system/context',
|
||||||
|
headers={'Authorization': f'Bearer {created["key"]}'},
|
||||||
|
)
|
||||||
|
assert bearer_response.status_code == 200
|
||||||
|
assert (await bearer_response.get_json())['data']['api_key_id'] == created['uuid']
|
||||||
|
|
||||||
|
jwt_response = await client.get(
|
||||||
|
'/api/v1/system/context',
|
||||||
|
headers={'Authorization': f'Bearer {owner_token}'},
|
||||||
|
)
|
||||||
|
assert jwt_response.status_code == 401
|
||||||
|
|
||||||
|
revoke_response = await client.delete(
|
||||||
|
f'/api/v1/apikeys/{created["id"]}',
|
||||||
|
headers=_auth(owner_token, workspace_uuid),
|
||||||
|
)
|
||||||
|
assert revoke_response.status_code == 200
|
||||||
|
|
||||||
|
revoked_response = await client.get(
|
||||||
|
'/api/v1/system/context',
|
||||||
|
headers={'X-API-Key': created['key']},
|
||||||
|
)
|
||||||
|
assert revoked_response.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
async def test_cloud_projection_is_selected_explicitly_and_collaboration_runs_in_core(
|
async def test_cloud_projection_is_selected_explicitly_and_collaboration_runs_in_core(
|
||||||
workspace_api,
|
workspace_api,
|
||||||
):
|
):
|
||||||
|
|||||||
Reference in New Issue
Block a user