From 908bbb828a2f70994dd33c58307827324a93d482 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Mon, 24 Nov 2025 19:42:43 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D(backend)=20add=20resource=20server?= =?UTF-8?q?=20quickstart=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create initial resource server integration documentation based on existing service account documentation structure to help developers understand authentication flow and implementation requirements for external services consuming Meet's protected resources. --- docs/resource_server.yaml | 393 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 docs/resource_server.yaml diff --git a/docs/resource_server.yaml b/docs/resource_server.yaml new file mode 100644 index 00000000..b8a1c5ad --- /dev/null +++ b/docs/resource_server.yaml @@ -0,0 +1,393 @@ +openapi: 3.0.3 +info: + title: Meet External API + version: 1.0.0 + description: | + External API for room management with resource server authentication. + [[description by Oauth 2.0]](https://www.oauth.com/oauth2-servers/the-resource-server/) + + #### Authentication Flow + + 1. Authenticate with the authorization server using your credentials + 2. During authentication, request the scopes you need: `lasuite_visio` (mandatory) plus action-specific scopes + 3. Receive an access token and a refresh token that includes the requested scopes + 4. Use the access token in the `Authorization: Bearer ` header for all API requests + 5. When the access token expires, use the refresh token to obtain a new access token without re-authenticating + + #### Scopes + + * `lasuite_visio` - **Mandatory** Base scope required for any API access + * `lasuite_visio:rooms:list` – List rooms accessible to the delegated user. + * `lasuite_visio:rooms:retrieve` – Retrieve details of a specific room. + * `lasuite_visio:rooms:create` – Create new rooms. + * `lasuite_visio:rooms:update` – **Coming soon** Update existing rooms, e.g., add attendees to a room. + * `lasuite_visio:rooms:delete` – **Coming soon** Delete rooms generated by the application. + + #### Upcoming Features + + * **Add attendees to a room:** You will be able to update a room to include a list of attendees, allowing them to bypass the lobby system automatically. + * **Delete application-generated rooms:** Rooms created via the application can be deleted when no longer needed. + + contact: + name: API Support + email: antoine.lebaud@mail.numerique.gouv.fr + +servers: + - url: https://visio-sandbox.beta.numerique.gouv.fr/external-api/v1.0 + description: Sandbox server + +tags: + - name: Rooms + description: Room management operations + +paths: + /rooms: + get: + tags: + - Rooms + summary: List rooms + description: | + Returns a list of rooms accessible to the authenticated user. + Only rooms where the delegated user has access will be returned. + operationId: listRooms + security: + - BearerAuth: [rooms:list] + parameters: + - name: page + in: query + description: Page number for pagination + schema: + type: integer + minimum: 1 + default: 1 + - name: page_size + in: query + description: Number of items per page + schema: + type: integer + minimum: 1 + maximum: 100 + default: 20 + responses: + '200': + description: List of accessible rooms + content: + application/json: + schema: + type: object + properties: + count: + type: integer + description: Total number of rooms + next: + type: string + nullable: true + description: URL to next page + previous: + type: string + nullable: true + description: URL to previous page + results: + type: array + items: + $ref: '#/components/schemas/Room' + examples: + roomList: + summary: Paginated room list + value: + count: 2 + next: "https://visio-sandbox.beta.numerique.gouv.fr/external-api/v1.0/rooms?page=2" + previous: null + results: + - id: "7c9e6679-7425-40de-944b-e07fc1f90ae7" + slug: "aae-erez-aaz" + access_level: "trusted" + url: "https://visio-sandbox.beta.numerique.gouv.fr/aae-erez-aaz" + telephony: + enabled: true + pin_code: "123456" + phone_number: "+1-555-0100" + default_country: "US" + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/ForbiddenError' + + post: + tags: + - Rooms + summary: Create a room + description: | + Creates a new room with secure defaults for external API usage. + + **Restrictions:** + - Rooms are always created with `trusted` access (no public rooms via API) + - Room access_level can be updated from the webapp interface. + + **Defaults:** + - Delegated user is set as owner + - Room slug auto-generated for uniqueness + - Telephony PIN auto-generated when enabled + - Creation tracked with application client_id for auditing + operationId: createRoom + security: + - BearerAuth: [rooms:create] + requestBody: + required: false + content: + application/json: + schema: + $ref: '#/components/schemas/RoomCreate' + examples: + emptyBody: + summary: No parameters (default) + value: {} + responses: + '201': + description: Room created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Room' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/ForbiddenError' + + /rooms/{id}: + get: + tags: + - Rooms + summary: Retrieve a room + description: Get detailed information about a specific room by its ID + operationId: retrieveRoom + security: + - BearerAuth: [rooms:retrieve] + parameters: + - name: id + in: path + required: true + description: Room UUID + schema: + type: string + format: uuid + responses: + '200': + description: Room details + content: + application/json: + schema: + $ref: '#/components/schemas/Room' + examples: + room: + summary: Room details + value: + id: "7c9e6679-7425-40de-944b-e07fc1f90ae7" + slug: "aae-erez-aaz" + access_level: "trusted" + url: "https://visio-sandbox.beta.numerique.gouv.fr/aae-erez-aaz" + telephony: + enabled: true + pin_code: "123456" + phone_number: "+1-555-0100" + default_country: "US" + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/ForbiddenError' + '404': + $ref: '#/components/responses/RoomNotFoundError' + +components: + securitySchemes: + BearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: | + JWT token obtained from the `/application/token` endpoint. + Include in requests as: `Authorization: Bearer ` + + schemas: + TokenRequest: + type: object + required: + - client_id + - client_secret + - grant_type + - scope + properties: + client_id: + type: string + description: Application client identifier + example: "550e8400-e29b-41d4-a716-446655440000" + client_secret: + type: string + format: password + writeOnly: true + description: Application secret key + example: "1234567890abcdefghijklmnopqrstuvwxyz" + grant_type: + type: string + enum: + - client_credentials + description: OAuth2 grant type (must be 'client_credentials') + example: "client_credentials" + scope: + type: string + format: email + description: | + Email address of the user to delegate. + The application will act on behalf of this user. + Note: This parameter is named 'scope' to align with OAuth2 conventions, + but accepts an email address to identify the user. This design allows + for future extensibility. + example: "user@example.com" + + TokenResponse: + type: object + properties: + access_token: + type: string + description: JWT access token + example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtZWV0LWFwaSIsImF1ZCI6Im1lZXQtY2xpZW50cyIsImlhdCI6MTcwOTQ5MTIwMCwiZXhwIjoxNzA5NDk0ODAwLCJjbGllbnRfaWQiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAiLCJzY29wZSI6InJvb21zOmxpc3Qgcm9vbXM6cmV0cmlldmUgcm9vbXM6Y3JlYXRlIiwidXNlcl9pZCI6IjdiOGQ5YzQwLTNhMmItNGVkZi04NzFjLTJmM2Q0ZTVmNmE3YiIsImRlbGVnYXRlZCI6dHJ1ZX0.signature" + token_type: + type: string + description: Token type (always 'Bearer') + example: "Bearer" + expires_in: + type: integer + description: Token lifetime in seconds + example: 3600 + scope: + type: string + description: Space-separated list of granted permission scopes + example: "rooms:list rooms:retrieve rooms:create" + + RoomCreate: + type: object + description: Empty object - all room properties are auto-generated + properties: {} + + Room: + type: object + properties: + id: + type: string + format: uuid + readOnly: true + description: Unique room identifier + example: "7c9e6679-7425-40de-944b-e07fc1f90ae7" + slug: + type: string + readOnly: true + description: URL-friendly room identifier (auto-generated) + example: "aze-eere-zer" + access_level: + type: string + readOnly: true + description: Room access level (always 'trusted' for API-created rooms) + example: "trusted" + url: + type: string + format: uri + readOnly: true + description: Full URL to access the room + example: "https://visio-sandbox.beta.numerique.gouv.fr/aze-eere-zer" + telephony: + type: object + readOnly: true + description: Telephony dial-in information (if enabled) + properties: + enabled: + type: boolean + description: Whether telephony is available + example: true + pin_code: + type: string + description: PIN code for dial-in access + example: "123456" + phone_number: + type: string + description: Phone number to dial + example: "+1-555-0100" + default_country: + type: string + description: Default country code + example: "US" + + OAuthError: + type: object + description: OAuth2-compliant error response + properties: + error: + type: string + description: Human-readable error description + example: "Invalid credentials" + + Error: + type: object + properties: + detail: + type: string + description: Error message + example: "Invalid token." + + ValidationError: + type: object + properties: + field_name: + type: array + items: + type: string + description: List of validation errors for this field + example: ["This field is required."] + + responses: + UnauthorizedError: + description: The access token is expired, revoked, malformed, or invalid for other reasons. The client can obtain a new access token and try again. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + invalidToken: + summary: Invalid token + value: + error: "Invalid token." + + ForbiddenError: + description: Insufficient scope for this operation + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + insufficientScope: + summary: Missing required scope + value: + detail: "Insufficient permissions. Required scope: 'rooms:xxxx'" + + RoomNotFoundError: + description: Room not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + roomNotFound: + summary: Room does not exist + value: + detail: "Not found." + + BadRequestError: + description: Invalid request data + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + examples: + validationError: + summary: Field validation failed + value: + scope: ["Invalid email address."]