mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
SMQ-2735 - Add PATs README and API docs (#2737)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
This commit is contained in:
@@ -25,6 +25,11 @@ tags:
|
||||
externalDocs:
|
||||
description: Find out more about keys
|
||||
url: https://docs.supermq.abstractmachines.fr/
|
||||
- name: PATs
|
||||
description: Everything about your Personal Access Tokens.
|
||||
externalDocs:
|
||||
description: Find out more about Personal Access Tokens
|
||||
url: https://docs.supermq.abstractmachines.fr/
|
||||
- name: Health
|
||||
description: Service health check endpoint.
|
||||
externalDocs:
|
||||
@@ -97,6 +102,299 @@ paths:
|
||||
description: A non-existent entity request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats:
|
||||
post:
|
||||
operationId: createPAT
|
||||
tags:
|
||||
- PATs
|
||||
summary: Create a new Personal Access Token
|
||||
description: |
|
||||
Creates a new Personal Access Token (PAT) for the authenticated user.
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/CreatePATRequest"
|
||||
responses:
|
||||
"201":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
get:
|
||||
operationId: listPATs
|
||||
tags:
|
||||
- PATs
|
||||
summary: List all Personal Access Tokens
|
||||
description: |
|
||||
Lists all Personal Access Tokens (PATs) for the authenticated user.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/PATsPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
operationId: clearAllPATs
|
||||
tags:
|
||||
- PATs
|
||||
summary: Remove all Personal Access Tokens
|
||||
description: |
|
||||
Removes all Personal Access Tokens (PATs) for the authenticated user.
|
||||
responses:
|
||||
"200":
|
||||
description: All PATs removed successfully.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}:
|
||||
get:
|
||||
operationId: retrievePAT
|
||||
tags:
|
||||
- PATs
|
||||
summary: Retrieve a Personal Access Token
|
||||
description: |
|
||||
Retrieves details of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
operationId: deletePAT
|
||||
tags:
|
||||
- PATs
|
||||
summary: Delete a Personal Access Token
|
||||
description: |
|
||||
Deletes a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
responses:
|
||||
"204":
|
||||
description: PAT deleted successfully.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/name:
|
||||
patch:
|
||||
operationId: updatePATName
|
||||
tags:
|
||||
- PATs
|
||||
summary: Update Personal Access Token name
|
||||
description: |
|
||||
Updates the name of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/UpdatePATNameRequest"
|
||||
responses:
|
||||
"202":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/description:
|
||||
patch:
|
||||
operationId: updatePATDescription
|
||||
tags:
|
||||
- PATs
|
||||
summary: Update Personal Access Token description
|
||||
description: |
|
||||
Updates the description of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/UpdatePATDescriptionRequest"
|
||||
responses:
|
||||
"202":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/secret/reset:
|
||||
patch:
|
||||
operationId: resetPATSecret
|
||||
tags:
|
||||
- PATs
|
||||
summary: Reset Personal Access Token secret
|
||||
description: |
|
||||
Resets the secret of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ResetPATSecretRequest"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/secret/revoke:
|
||||
patch:
|
||||
operationId: revokePATSecret
|
||||
tags:
|
||||
- PATs
|
||||
summary: Revoke Personal Access Token secret
|
||||
description: |
|
||||
Revokes the secret of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
responses:
|
||||
"204":
|
||||
description: PAT secret revoked successfully.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/scope:
|
||||
get:
|
||||
operationId: listScopes
|
||||
tags:
|
||||
- PATs
|
||||
summary: List scopes for a Personal Access Token
|
||||
description: |
|
||||
Lists all scopes for a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/ScopesPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
operationId: clearAllScopes
|
||||
tags:
|
||||
- PATs
|
||||
summary: Remove all scopes from a Personal Access Token
|
||||
description: |
|
||||
Removes all scopes from a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
responses:
|
||||
"200":
|
||||
description: All scopes removed successfully.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/scope/add:
|
||||
patch:
|
||||
operationId: addScope
|
||||
tags:
|
||||
- PATs
|
||||
summary: Add scope to a Personal Access Token
|
||||
description: |
|
||||
Adds a scope to a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/AddScopeRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Scope added successfully.
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/scope/remove:
|
||||
patch:
|
||||
operationId: removeScope
|
||||
tags:
|
||||
- PATs
|
||||
summary: Remove scope from a Personal Access Token
|
||||
description: |
|
||||
Removes a scope from a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/RemoveScopeRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Scope removed successfully.
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
@@ -111,6 +409,135 @@ paths:
|
||||
|
||||
components:
|
||||
schemas:
|
||||
PAT:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "c5747f2f-2a7c-4fe1-b41a-51a5ae290945"
|
||||
description: Personal Access Token unique identifier
|
||||
user_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "9118de62-c680-46b7-ad0a-21748a52833a"
|
||||
description: User ID of the PAT owner
|
||||
name:
|
||||
type: string
|
||||
example: "My PAT"
|
||||
description: Name of the Personal Access Token
|
||||
description:
|
||||
type: string
|
||||
example: "Token for automation"
|
||||
description: Description of the Personal Access Token
|
||||
secret:
|
||||
type: string
|
||||
example: "pat_1234567890abcdef"
|
||||
description: Secret value of the Personal Access Token
|
||||
issued_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26T13:31:52Z"
|
||||
description: Time when the PAT was issued
|
||||
expires_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2020-11-26T13:31:52Z"
|
||||
description: Time when the PAT expires
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26T13:31:52Z"
|
||||
description: Time when the PAT was last updated
|
||||
last_used_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26T13:31:52Z"
|
||||
description: Time when the PAT was last used
|
||||
revoked:
|
||||
type: boolean
|
||||
example: false
|
||||
description: Whether the PAT is revoked
|
||||
revoked_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26T13:31:52Z"
|
||||
description: Time when the PAT was revoked
|
||||
|
||||
PATsPage:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Total number of PATs
|
||||
offset:
|
||||
type: integer
|
||||
example: 0
|
||||
description: Number of items to skip during retrieval
|
||||
limit:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Size of the subset to retrieve
|
||||
pats:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/PAT"
|
||||
description: List of Personal Access Tokens
|
||||
|
||||
Scope:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "c5747f2f-2a7c-4fe1-b41a-51a5ae290945"
|
||||
description: Scope unique identifier
|
||||
pat_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "9118de62-c680-46b7-ad0a-21748a52833a"
|
||||
description: PAT ID this scope belongs to
|
||||
optional_domain_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "bb7edb32-2eac-4aad-aebe-ed96fe073879"
|
||||
description: Optional domain ID for the scope
|
||||
entity_type:
|
||||
type: string
|
||||
enum: [groups, channels, clients, domains, users, dashboards, messages]
|
||||
example: "groups"
|
||||
description: Type of entity the scope applies to
|
||||
entity_id:
|
||||
type: string
|
||||
example: "*"
|
||||
description: ID of the entity the scope applies to. '*' means all entities of the specified type.
|
||||
operation:
|
||||
type: string
|
||||
enum: [create, read, list, update, delete, share, unshare, publish, subscribe]
|
||||
example: "read"
|
||||
description: Operation allowed by this scope
|
||||
|
||||
ScopesPage:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Total number of scopes
|
||||
offset:
|
||||
type: integer
|
||||
example: 0
|
||||
description: Number of items to skip during retrieval
|
||||
limit:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Size of the subset to retrieve
|
||||
scopes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Scope"
|
||||
description: List of scopes
|
||||
Key:
|
||||
type: object
|
||||
properties:
|
||||
@@ -146,6 +573,14 @@ components:
|
||||
that means that Key is valid indefinitely.
|
||||
|
||||
parameters:
|
||||
PatID:
|
||||
name: patID
|
||||
description: Personal Access Token ID.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
DomainID:
|
||||
name: domainID
|
||||
description: Unique domain identifier.
|
||||
@@ -233,6 +668,104 @@ components:
|
||||
required: false
|
||||
|
||||
requestBodies:
|
||||
CreatePATRequest:
|
||||
description: JSON-formatted document describing PAT creation request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: "My PAT"
|
||||
description: Name of the Personal Access Token
|
||||
description:
|
||||
type: string
|
||||
example: "Token for automation"
|
||||
description: Description of the Personal Access Token
|
||||
duration:
|
||||
type: string
|
||||
example: "30d"
|
||||
description: Duration for which the PAT is valid. Format is a duration string (e.g. "30d", "24h", "1y").
|
||||
|
||||
UpdatePATNameRequest:
|
||||
description: JSON-formatted document describing PAT name update request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: "New PAT Name"
|
||||
description: New name for the Personal Access Token
|
||||
|
||||
UpdatePATDescriptionRequest:
|
||||
description: JSON-formatted document describing PAT description update request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- description
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
example: "New PAT Description"
|
||||
description: New description for the Personal Access Token
|
||||
|
||||
ResetPATSecretRequest:
|
||||
description: JSON-formatted document describing PAT secret reset request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
duration:
|
||||
type: string
|
||||
example: "30d"
|
||||
description: Duration for which the new PAT secret is valid. Format is a duration string (e.g. "30d", "24h", "1y").
|
||||
|
||||
AddScopeRequest:
|
||||
description: JSON-formatted document describing add scope request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- scopes
|
||||
properties:
|
||||
scopes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Scope"
|
||||
description: List of scopes to add
|
||||
|
||||
RemoveScopeRequest:
|
||||
description: JSON-formatted document describing remove scope request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- scopes_id
|
||||
properties:
|
||||
scopes_id:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
description: List of scope IDs to remove
|
||||
KeyRequest:
|
||||
description: JSON-formatted document describing key request.
|
||||
required: true
|
||||
@@ -252,6 +785,26 @@ components:
|
||||
description: Number of seconds issued token is valid for.
|
||||
|
||||
responses:
|
||||
PATRes:
|
||||
description: Personal Access Token data.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PAT"
|
||||
|
||||
PATsPageRes:
|
||||
description: Page of Personal Access Tokens.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PATsPage"
|
||||
|
||||
ScopesPageRes:
|
||||
description: Page of scopes.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ScopesPage"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
KeyRes:
|
||||
|
||||
+275
@@ -85,6 +85,8 @@ The service is configured using the environment variables presented in the follo
|
||||
| SMQ_AUTH_ACCESS_TOKEN_DURATION | The access token expiration period | 1h |
|
||||
| SMQ_AUTH_REFRESH_TOKEN_DURATION | The refresh token expiration period | 24h |
|
||||
| SMQ_AUTH_INVITATION_DURATION | The invitation token expiration period | 168h |
|
||||
| SMQ_AUTH_CACHE_URL | Redis URL for caching PAT scopes | redis://localhost:6379/0 |
|
||||
| SMQ_AUTH_CACHE_KEY_DURATION | Duration for which PAT scope cache keys are valid | 10m |
|
||||
| SMQ_SPICEDB_HOST | SpiceDB host address | localhost |
|
||||
| SMQ_SPICEDB_PORT | SpiceDB host port | 50051 |
|
||||
| SMQ_SPICEDB_PRE_SHARED_KEY | SpiceDB pre-shared key | 12345678 |
|
||||
@@ -152,6 +154,279 @@ $GOBIN/supermq-auth
|
||||
Setting `SMQ_AUTH_HTTP_SERVER_CERT` and `SMQ_AUTH_HTTP_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key.
|
||||
Setting `SMQ_AUTH_GRPC_SERVER_CERT` and `SMQ_AUTH_GRPC_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key. Setting `SMQ_AUTH_GRPC_SERVER_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs. Setting `SMQ_AUTH_GRPC_CLIENT_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs.
|
||||
|
||||
## Personal Access Tokens (PATs)
|
||||
|
||||
Personal Access Tokens (PATs) provide a secure way to authenticate with SuperMQ APIs without using your primary credentials. They are particularly useful for automation, CI/CD pipelines, and integrating with third-party services.
|
||||
|
||||
### Overview
|
||||
|
||||
PATs in SuperMQ are designed with the following features:
|
||||
|
||||
- **Scoped Access**: Each token can be limited to specific operations on specific resources
|
||||
- **Expiration Control**: Set custom expiration times for tokens
|
||||
- **Revocable**: Tokens can be revoked at any time
|
||||
- **Auditable**: Track when tokens were last used
|
||||
- **Secure**: Tokens are stored as hashes, not in plaintext
|
||||
|
||||
### Token Structure
|
||||
|
||||
A PAT consists of three parts separated by underscores:
|
||||
```
|
||||
pat_<encoded-user-and-pat-id>_<random-string>
|
||||
```
|
||||
|
||||
Where:
|
||||
- `pat` is a fixed prefix
|
||||
- `<encoded-user-and-pat-id>` is a base64-encoded combination of the user ID and PAT ID
|
||||
- `<random-string>` is a randomly generated string for additional security
|
||||
|
||||
### PAT Operations
|
||||
|
||||
SuperMQ supports the following operations for PATs:
|
||||
|
||||
| Operation | Description |
|
||||
|-----------|-------------|
|
||||
| `create` | Create a new resource |
|
||||
| `read` | Read/view a resource |
|
||||
| `list` | List resources |
|
||||
| `update` | Update/modify a resource |
|
||||
| `delete` | Delete a resource |
|
||||
| `share` | Share a resource with others |
|
||||
| `unshare` | Remove sharing permissions |
|
||||
| `publish` | Publish messages to a channel |
|
||||
| `subscribe` | Subscribe to messages from a channel |
|
||||
|
||||
### Entity Types
|
||||
|
||||
PATs can be scoped to the following entity types:
|
||||
|
||||
| Entity Type | Description |
|
||||
|-------------|-------------|
|
||||
| `groups` | User groups |
|
||||
| `channels` | Communication channels |
|
||||
| `clients` | Client applications |
|
||||
| `domains` | Organizational domains |
|
||||
| `users` | User accounts |
|
||||
| `dashboards` | Dashboard interfaces |
|
||||
| `messages` | Message content |
|
||||
|
||||
### API Examples
|
||||
|
||||
#### Creating a PAT
|
||||
|
||||
```bash
|
||||
curl --location 'http://localhost:9001/pats' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer <access_token>' \
|
||||
--data '{
|
||||
"name": "test pat",
|
||||
"description": "testing pat",
|
||||
"duration": "24h"
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"id": "a2500226-95dc-4285-87e2-e693e4a0a976",
|
||||
"user_id": "user123",
|
||||
"name": "pat 1",
|
||||
"description": "for creating any client or channel",
|
||||
"secret": "pat_dXNlcjEyM19hMjUwMDIyNi05NWRjLTQyODUtODdlMi1lNjkzZTRhMGE5NzY=_randomstring...",
|
||||
"issued_at": "2025-02-27T11:20:59Z",
|
||||
"expires_at": "2025-02-28T11:20:59Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### Adding Scopes to a PAT
|
||||
|
||||
```bash
|
||||
curl --location --request PATCH 'http://localhost:9001/pats/a2500226-95dc-4285-87e2-e693e4a0a976/scope/add' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer <access_token>' \
|
||||
--data '{
|
||||
"scopes": [
|
||||
{
|
||||
"optional_domain_id": "c16c980a-9d4c-4793-8fb2-c81304cf1d9f",
|
||||
"entity_type": "clients",
|
||||
"operation": "create",
|
||||
"entity_id": "*"
|
||||
},
|
||||
{
|
||||
"optional_domain_id": "c16c980a-9d4c-4793-8fb2-c81304cf1d9f",
|
||||
"entity_type": "channels",
|
||||
"operation": "create",
|
||||
"entity_id": "cfbc6936-5748-4339-a8ef-37b64b02bc96"
|
||||
},
|
||||
{
|
||||
"entity_type": "dashboards",
|
||||
"optional_domain_id": "c16c980a-9d4c-4793-8fb2-c81304cf1d9f",
|
||||
"operation": "read",
|
||||
"entity_id": "*"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
#### Listing PATs
|
||||
|
||||
```bash
|
||||
curl --location 'http://localhost:9001/pats' \
|
||||
--header 'Authorization: Bearer <access_token>'
|
||||
```
|
||||
|
||||
#### Listing Scopes for a PAT
|
||||
|
||||
```bash
|
||||
curl --location 'http://localhost:9001/pats/a2500226-95dc-4285-87e2-e693e4a0a976/scopes' \
|
||||
--header 'Authorization: Bearer <access_token>'
|
||||
```
|
||||
|
||||
#### Revoking a PAT
|
||||
|
||||
```bash
|
||||
curl --location --request PATCH 'http://localhost:9001/pats/a2500226-95dc-4285-87e2-e693e4a0a976/revoke' \
|
||||
--header 'Authorization: Bearer <access_token>'
|
||||
```
|
||||
|
||||
#### Resetting a PAT Secret
|
||||
|
||||
```bash
|
||||
curl --location --request PATCH 'http://localhost:9001/pats/a2500226-95dc-4285-87e2-e693e4a0a976/reset' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer <access_token>' \
|
||||
--data '{
|
||||
"duration": "720h"
|
||||
}'
|
||||
```
|
||||
|
||||
### Using PATs for Authentication
|
||||
|
||||
When making API requests, include the PAT in the Authorization header:
|
||||
|
||||
```
|
||||
Authorization: Bearer pat_<encoded-user-and-pat-id>_<random-string>
|
||||
```
|
||||
|
||||
#### Example: Creating a Client Using PAT
|
||||
|
||||
```bash
|
||||
curl --location 'http://localhost:9006/c16c980a-9d4c-4793-8fb2-c81304cf1d9f/clients' \
|
||||
--header 'accept: application/json' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer pat_etKoiXKTR6a0zdgsBHC00qJQAiaV3EKFh+Lmk+SgqXY=_u7@5fyjgti9V@#Bw^bS*SPmX3OnH=HTvKwmIbxIuyBjoI|6FASo9egjKD^u-M$b|2Dpt3CXZtv&4k+hmYYjk&C$57AV59P%-iDV0' \
|
||||
--data '{
|
||||
"name": "test client",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
],
|
||||
"metadata":{"units":"km"},
|
||||
"status": "enabled"
|
||||
}'
|
||||
```
|
||||
|
||||
This example shows how to create a client in a specific domain (`c16c980a-9d4c-4793-8fb2-c81304cf1d9f`) using a PAT for authentication. The PAT must have the appropriate scope (e.g., `clients` entity type with `create` operation) for this domain.
|
||||
|
||||
### Wildcard Entity IDs
|
||||
|
||||
When defining scopes for PATs, you can use the wildcard character `*` for the `entity_id` field to grant permissions for all entities of a specific type. This is particularly useful for automation tasks that need to operate on multiple resources.
|
||||
|
||||
For example:
|
||||
- `"entity_id": "*"` - Grants permission for all entities of the specified type
|
||||
- `"entity_id": "specific-id"` - Grants permission only for the entity with the specified ID
|
||||
|
||||
Using wildcards should be done carefully, as they grant broader permissions. Always follow the principle of least privilege by granting only the permissions necessary for the intended use case.
|
||||
|
||||
### Scope Examples
|
||||
|
||||
#### Allow Creating Any Client in a Domain
|
||||
|
||||
```json
|
||||
{
|
||||
"optional_domain_id": "domain_id",
|
||||
"entity_type": "clients",
|
||||
"operation": "create",
|
||||
"entity_id": "*"
|
||||
}
|
||||
```
|
||||
|
||||
This scope allows the PAT to create any client within the specified domain. The wildcard `*` for `entity_id` means the token can create any client, not just a specific one.
|
||||
|
||||
#### Allow Publishing to a Specific Channel
|
||||
|
||||
```json
|
||||
{
|
||||
"optional_domain_id": "domain_id",
|
||||
"entity_type": "channels",
|
||||
"operation": "publish",
|
||||
"entity_id": "channel_id"
|
||||
}
|
||||
```
|
||||
|
||||
This scope restricts the PAT to only publish to a specific channel (`channel_id`) within the specified domain. No wildcard is used, so the permission is limited to just this one channel.
|
||||
|
||||
#### Allow Reading All Dashboards
|
||||
|
||||
```json
|
||||
{
|
||||
"optional_domain_id": "domain_id",
|
||||
"entity_type": "dashboards",
|
||||
"operation": "read",
|
||||
"entity_id": "*"
|
||||
}
|
||||
```
|
||||
|
||||
This scope allows the PAT to read all dashboards within the specified domain. The wildcard `*` for `entity_id` means the token can read any dashboard in that domain.
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Limit Scope**: Always use the principle of least privilege when creating PATs
|
||||
2. **Set Expirations**: Use reasonable expiration times for tokens
|
||||
3. **Rotate Regularly**: Reset token secrets periodically
|
||||
4. **Audit Usage**: Monitor when tokens are used
|
||||
5. **Revoke Unused**: Remove tokens that are no longer needed
|
||||
|
||||
### Implementation Details
|
||||
|
||||
PATs are stored in the database with the following schema:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS pats (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
name VARCHAR(254) NOT NULL,
|
||||
user_id VARCHAR(36),
|
||||
description TEXT,
|
||||
secret TEXT,
|
||||
issued_at TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
updated_at TIMESTAMP,
|
||||
revoked BOOLEAN,
|
||||
revoked_at TIMESTAMP,
|
||||
last_used_at TIMESTAMP,
|
||||
UNIQUE (id, name, secret)
|
||||
)
|
||||
|
||||
CREATE TABLE IF NOT EXISTS pat_scopes (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pat_id VARCHAR(36) REFERENCES pats(id) ON DELETE CASCADE,
|
||||
optional_domain_id VARCHAR(36),
|
||||
entity_type VARCHAR(50) NOT NULL,
|
||||
operation VARCHAR(50) NOT NULL,
|
||||
entity_id VARCHAR(50) NOT NULL,
|
||||
UNIQUE (pat_id, optional_domain_id, entity_type, operation, entity_id)
|
||||
)
|
||||
```
|
||||
|
||||
### Authorization
|
||||
|
||||
When a PAT is used for authentication:
|
||||
|
||||
1. The system parses the token to extract the user ID and PAT ID
|
||||
2. It verifies the token hasn't been revoked or expired
|
||||
3. It checks if the requested operation is allowed by the token's scopes
|
||||
4. If all checks pass, the operation is authorized
|
||||
|
||||
## Usage
|
||||
|
||||
For more information about service capabilities and its usage, please check out the [API documentation](https://docs.api.supermq.abstractmachines.fr/?urls.primaryName=auth.yml).
|
||||
|
||||
@@ -54,7 +54,6 @@ const (
|
||||
envPrefixHTTP = "SMQ_AUTH_HTTP_"
|
||||
envPrefixGrpc = "SMQ_AUTH_GRPC_"
|
||||
envPrefixDB = "SMQ_AUTH_DB_"
|
||||
envPrefixPATDB = "SMQ_AUTH_PAT_DB_"
|
||||
defDB = "auth"
|
||||
defSvcHTTPPort = "8189"
|
||||
defSvcGRPCPort = "8181"
|
||||
|
||||
Reference in New Issue
Block a user