openapi: 3.1.0 info: title: Latch Vector SSO API description: >- Public API reference for the Latch Vector SSO / identity service. Operator-only internal and platform endpoints are intentionally excluded. version: v1 servers: - url: http://localhost:9900 description: Generated server url security: - bearerAuth: [] tags: - name: API clients description: >- Register and list machine-to-machine clients (the client_credentials grant). Requires the CLIENT_MANAGE permission on a user token. paths: /api/webhooks/{id}: put: tags: - webhook-controller operationId: update parameters: - name: id in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/WebhookSummary' delete: tags: - webhook-controller operationId: delete parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK /api/users/{id}: put: tags: - user-controller operationId: update_1 parameters: - name: id in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateUserRequest' required: true responses: '200': description: OK /api/roles/{roleId}/permissions: put: tags: - role-controller operationId: updatePermissions parameters: - name: roleId in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateRolePermissionsRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/RoleResponse' /api/organizations/{id}: put: tags: - organization-controller operationId: update_2 parameters: - name: id in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateOrganizationRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/Organization' /api/applications/{applicationId}: put: tags: - application-controller operationId: update_3 parameters: - name: applicationId in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateApplicationRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/ApplicationResponse' /api/webhooks: get: tags: - webhook-controller operationId: list parameters: - name: organizationId in: query required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/WebhookSummary' post: tags: - webhook-controller operationId: register requestBody: content: application/json: schema: $ref: '#/components/schemas/RegisterRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/Registered' /api/webhooks/{id}/rotate-secret: post: tags: - webhook-controller operationId: rotateSecret parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/SecretResponse' /api/users: get: tags: - user-controller operationId: list_1 parameters: - name: organizationId in: query required: true schema: type: integer format: int64 - name: size in: query required: false schema: type: integer format: int32 default: 200 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/UserSummary' post: tags: - user-controller operationId: create requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateUserRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/CreateUserResponse' /api/users/{id}/password-setup-link: post: tags: - user-controller operationId: passwordSetupLink parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/SetupLinkResponse' /api/users/{id}/erase: post: tags: - data-subject-controller operationId: eraseUser parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK /api/users/{id}/enable: post: tags: - user-controller operationId: enable parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK /api/users/{id}/disable: post: tags: - user-controller operationId: disable parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK /api/roles: get: tags: - role-controller operationId: list_2 parameters: - name: organizationId in: query required: true schema: type: integer format: int64 - name: size in: query required: false schema: type: integer format: int32 default: 200 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/RoleResponse' post: tags: - role-controller operationId: create_1 requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateRoleRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/RoleResponse' /api/roles/{roleId}/revoke: post: tags: - role-controller operationId: revoke parameters: - name: roleId in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/RoleAssignmentRequest' required: true responses: '200': description: OK /api/roles/{roleId}/assign: post: tags: - role-controller operationId: assign parameters: - name: roleId in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/RoleAssignmentRequest' required: true responses: '200': description: OK /api/organizations: get: tags: - organization-controller operationId: list_3 parameters: - name: after in: query required: false schema: type: string - name: size in: query required: false schema: type: integer format: int32 default: 100 responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/CursorSliceOrganization' post: tags: - organization-controller operationId: create_2 requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateOrganizationRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/Organization' /api/organizations/{id}/suspend: post: tags: - organization-controller operationId: suspend_1 parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/Organization' /api/organizations/{id}/activate: post: tags: - organization-controller operationId: activate_1 parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/Organization' /api/mfa/setup/confirm: post: tags: - mfa-setup-controller operationId: confirmSetup requestBody: content: application/json: schema: $ref: '#/components/schemas/MfaConfirmRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/RecoveryCodesResponse' /api/mfa/setup/begin: post: tags: - mfa-setup-controller operationId: beginSetup responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/MfaSetupResponse' /api/mfa/disable: post: tags: - mfa-setup-controller operationId: disable_1 responses: '200': description: OK /api/import/validate: post: tags: - import-controller operationId: validate requestBody: content: application/json: schema: $ref: '#/components/schemas/ImportRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/ImportReport' /api/import/commit: post: tags: - import-controller operationId: commit requestBody: content: application/json: schema: $ref: '#/components/schemas/ImportRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/ImportReport' /api/clients: get: tags: - API clients summary: List an organization's API clients description: Returns client ids, names and scopes — never secrets. operationId: list_4 parameters: - name: organizationId in: query required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/ClientSummary' post: tags: - API clients summary: Register a new API client description: >- Creates a machine client for an organization. The response carries the plaintext secret EXACTLY ONCE — it is stored only as a hash and cannot be retrieved again. The client then authenticates at POST /oauth2/token. operationId: register_1 requestBody: content: application/json: schema: $ref: '#/components/schemas/RegisterClientRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/ClientCredentialsResponse' /api/auth/social/{provider}: post: tags: - auth-controller operationId: socialLogin parameters: - name: provider in: path required: true schema: type: string - name: web in: query required: false schema: type: boolean default: false requestBody: content: application/json: schema: $ref: '#/components/schemas/SocialLoginRequest' required: true responses: '200': description: OK content: '*/*': schema: type: object /api/auth/refresh: post: tags: - auth-controller operationId: refresh requestBody: content: application/json: schema: $ref: '#/components/schemas/RefreshRequest' responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/TokenPairResponse' /api/auth/password/reset: post: tags: - password-controller operationId: reset requestBody: content: application/json: schema: $ref: '#/components/schemas/ResetPasswordRequest' required: true responses: '200': description: OK /api/auth/password/forgot: post: tags: - password-controller operationId: forgot requestBody: content: application/json: schema: $ref: '#/components/schemas/ForgotPasswordRequest' required: true responses: '200': description: OK /api/auth/mfa/verify: post: tags: - auth-controller operationId: verifyMfa parameters: - name: web in: query required: false schema: type: boolean default: false requestBody: content: application/json: schema: $ref: '#/components/schemas/MfaVerifyRequest' required: true responses: '200': description: OK content: '*/*': schema: type: object /api/auth/logout: post: tags: - auth-controller operationId: logout requestBody: content: application/json: schema: $ref: '#/components/schemas/LogoutRequest' responses: '200': description: OK /api/auth/login: post: tags: - auth-controller operationId: login parameters: - name: web in: query required: false schema: type: boolean default: false requestBody: content: application/json: schema: $ref: '#/components/schemas/LoginRequest' required: true responses: '200': description: OK content: '*/*': schema: type: object /api/applications: get: tags: - application-controller operationId: list_5 parameters: - name: organizationId in: query required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/ApplicationResponse' post: tags: - application-controller operationId: create_3 requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateApplicationRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/ApplicationResponse' /api/applications/{applicationId}/permissions: get: tags: - application-controller operationId: listPermissions parameters: - name: applicationId in: path required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/PermissionResponse' post: tags: - application-controller operationId: addPermission parameters: - name: applicationId in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/CreatePermissionRequest' required: true responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/PermissionResponse' /api/users/{id}/export: get: tags: - data-subject-controller operationId: exportUserData parameters: - name: id in: path required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: type: object additionalProperties: {} /api/users/me/export: get: tags: - data-subject-controller operationId: exportOwnData responses: '200': description: OK content: '*/*': schema: type: object additionalProperties: {} /api/users/me/devices: get: tags: - device-controller operationId: myDevices responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/DeviceView' /api/tenant-hierarchy/visible-orgs/{parentOrgId}: get: tags: - tenant-hierarchy-controller operationId: visibleOrgs parameters: - name: parentOrgId in: path required: true schema: type: integer format: int64 - name: after in: query required: false schema: type: string - name: size in: query required: false schema: type: integer format: int32 default: 100 responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/VisibleOrgsResponse' /api/organizations/search: get: tags: - organization-controller operationId: search parameters: - name: q in: query required: false schema: type: string default: '' - name: status in: query required: false schema: type: string enum: - ACTIVE - SUSPENDED - name: size in: query required: false schema: type: integer format: int32 default: 50 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/Organization' /api/import/jobs: get: tags: - import-controller operationId: jobs parameters: - name: limit in: query required: false schema: type: integer format: int32 default: 50 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/JobSummary' /api/audit: get: tags: - audit-controller operationId: list_6 parameters: - name: organizationId in: query required: true schema: type: integer format: int64 - name: action in: query required: false schema: type: string - name: userId in: query required: false schema: type: integer format: int64 - name: q in: query required: false schema: type: string - name: from in: query required: false schema: type: string format: date-time - name: to in: query required: false schema: type: string format: date-time - name: size in: query required: false schema: type: integer format: int32 default: 100 responses: '200': description: OK content: '*/*': schema: type: array items: $ref: '#/components/schemas/AuditEntry' /api/applications/quota: get: tags: - application-controller operationId: quota parameters: - name: organizationId in: query required: true schema: type: integer format: int64 responses: '200': description: OK content: '*/*': schema: $ref: '#/components/schemas/QuotaResponse' /api/users/me/devices/{deviceId}: delete: tags: - device-controller operationId: revoke_1 parameters: - name: deviceId in: path required: true schema: type: string responses: '200': description: OK /api/applications/{applicationId}/permissions/{permissionId}: delete: tags: - application-controller operationId: deletePermission parameters: - name: applicationId in: path required: true schema: type: integer format: int64 - name: permissionId in: path required: true schema: type: integer format: int64 responses: '200': description: OK /oauth2/token: post: tags: - OAuth2 (machine tokens) summary: Exchange client credentials for an access token description: >- The `client_credentials` grant. Authenticate with HTTP Basic using the `clientId` as username and the client secret as password, and post `grant_type=client_credentials`. Returns a short-lived access token whose `sub`/`aud` is the client id and which carries the client's `org_id` and `tenant_id`. No `uid`, no user permissions. requestBody: content: application/x-www-form-urlencoded: schema: type: object properties: grant_type: type: string default: client_credentials description: Must be `client_credentials` for machine-to-machine. scope: type: string description: >- Optional. Space-separated, a subset of the client's registered scopes. Omit to receive all of them. required: - grant_type required: true responses: '200': description: Access token issued content: application/json: schema: type: object properties: access_token: type: string description: Signed RS256 JWT. token_type: type: string default: Bearer expires_in: type: integer format: int32 description: Seconds until expiry (~900). scope: type: string '400': description: Unsupported grant, or a scope the client was not granted '401': description: Unknown client or wrong secret security: - clientBasicAuth: [] components: schemas: UpdateRequest: type: object properties: url: type: string eventTypes: type: array items: type: string active: type: boolean WebhookSummary: type: object properties: id: type: integer format: int64 applicationId: type: integer format: int64 url: type: string eventTypes: type: string active: type: boolean createdAt: type: string format: date-time UpdateUserRequest: type: object properties: fullName: type: string organizationId: type: integer format: int64 UpdateRolePermissionsRequest: type: object properties: permissionCodes: type: array items: type: string permissionIds: type: array items: type: integer format: int64 PermissionRef: type: object properties: id: type: integer format: int64 code: type: string applicationId: type: integer format: int64 RoleResponse: type: object properties: id: type: integer format: int64 organizationId: type: integer format: int64 name: type: string description: type: string scope: type: string permissions: type: array items: $ref: '#/components/schemas/PermissionRef' UpdateOrganizationRequest: type: object properties: name: type: string type: type: string Organization: type: object properties: id: type: integer format: int64 tenantId: type: integer format: int64 parentId: type: integer format: int64 path: type: string type: type: string name: type: string slug: type: string status: type: string enum: - ACTIVE - SUSPENDED expiresAt: type: string format: date-time createdAt: type: string format: date-time updatedAt: type: string format: date-time UpdateApplicationRequest: type: object properties: name: type: string minLength: 1 webRefreshTtlDays: type: integer format: int32 maximum: 180 minimum: 1 deviceRefreshTtlDays: type: integer format: int32 maximum: 180 minimum: 1 required: - name ApplicationResponse: type: object properties: id: type: integer format: int64 organizationId: type: integer format: int64 identifier: type: string name: type: string webRefreshTtlDays: type: integer format: int32 deviceRefreshTtlDays: type: integer format: int32 LimitsRequest: type: object properties: maxApplications: type: integer format: int32 RegisterRequest: type: object properties: organizationId: type: integer format: int64 applicationId: type: integer format: int64 url: type: string minLength: 1 eventTypes: type: array items: type: string required: - applicationId - organizationId - url Registered: type: object properties: id: type: integer format: int64 url: type: string secret: type: string eventTypes: type: string SecretResponse: type: object properties: id: type: integer format: int64 secret: type: string CreateUserRequest: type: object properties: organizationId: type: integer format: int64 email: type: string minLength: 1 fullName: type: string minLength: 1 password: type: string roleId: type: integer format: int64 required: - email - fullName - organizationId CreateUserResponse: type: object properties: id: type: integer format: int64 email: type: string organizationId: type: integer format: int64 SetupLinkResponse: type: object properties: token: type: string expiresAt: type: string format: date-time ProvisionRequest: type: object properties: orgName: type: string minLength: 1 adminEmail: type: string minLength: 1 adminFullName: type: string minLength: 1 ttlDays: type: integer format: int32 required: - adminEmail - adminFullName - orgName Provisioned: type: object properties: tenantId: type: integer format: int64 orgName: type: string slug: type: string adminEmail: type: string setupToken: type: string expiresAt: type: string format: date-time CreateRoleRequest: type: object properties: organizationId: type: integer format: int64 name: type: string minLength: 1 description: type: string permissionCodes: type: array items: type: string permissionIds: type: array items: type: integer format: int64 scope: type: string required: - name RoleAssignmentRequest: type: object properties: userId: type: integer format: int64 organizationId: type: integer format: int64 required: - organizationId - userId CreateOrganizationRequest: type: object properties: name: type: string minLength: 1 slug: type: string minLength: 1 parentId: type: integer format: int64 type: type: string required: - name - slug MfaConfirmRequest: type: object properties: code: type: string minLength: 1 required: - code RecoveryCodesResponse: type: object properties: recoveryCodes: type: array items: type: string MfaSetupResponse: type: object properties: otpAuthUri: type: string App: type: object properties: externalId: type: string orgExternalId: type: string identifier: type: string name: type: string Assignment: type: object properties: userExternalId: type: string roleExternalId: type: string orgExternalId: type: string ImportRequest: type: object properties: rootParentOrgId: type: integer format: int64 rootTenant: $ref: '#/components/schemas/NewTenant' organizations: type: array items: $ref: '#/components/schemas/Org' applications: type: array items: $ref: '#/components/schemas/App' permissions: type: array items: $ref: '#/components/schemas/Perm' roles: type: array items: $ref: '#/components/schemas/RoleDef' users: type: array items: $ref: '#/components/schemas/UserDef' assignments: type: array items: $ref: '#/components/schemas/Assignment' NewTenant: type: object properties: orgName: type: string slug: type: string Org: type: object properties: externalId: type: string name: type: string slug: type: string type: type: string parentExternalId: type: string Perm: type: object properties: externalId: type: string appExternalId: type: string code: type: string description: type: string RoleDef: type: object properties: externalId: type: string orgExternalId: type: string name: type: string description: type: string scope: type: string permissionCodes: type: array items: type: string permissionExternalIds: type: array items: type: string UserDef: type: object properties: externalId: type: string orgExternalId: type: string email: type: string fullName: type: string passwordBcrypt: type: string Counts: type: object properties: created: type: integer format: int32 updated: type: integer format: int32 skipped: type: integer format: int32 failed: type: integer format: int32 Error: type: object properties: entityType: type: string externalId: type: string field: type: string message: type: string ImportReport: type: object properties: jobId: type: integer format: int64 status: type: string dryRun: type: boolean tenantId: type: integer format: int64 rootOrgId: type: integer format: int64 counts: type: object additionalProperties: $ref: '#/components/schemas/Counts' errors: type: array items: $ref: '#/components/schemas/Error' invites: type: array items: $ref: '#/components/schemas/Invite' Invite: type: object properties: userExternalId: type: string email: type: string setupToken: type: string RegisterClientRequest: type: object properties: name: type: string minLength: 1 orgId: type: integer format: int64 applicationId: type: integer format: int64 scopes: type: array items: type: string required: - name - orgId ClientCredentialsResponse: type: object properties: clientId: type: string clientSecret: type: string DeviceInfo: type: object properties: deviceId: type: string name: type: string platform: type: string SocialLoginRequest: type: object properties: idToken: type: string minLength: 1 audience: type: string device: $ref: '#/components/schemas/DeviceInfo' required: - idToken RefreshRequest: type: object properties: refreshToken: type: string minLength: 1 audience: type: string required: - refreshToken TokenPairResponse: type: object properties: accessToken: type: string refreshToken: type: string tokenType: type: string expiresInSeconds: type: integer format: int64 deviceId: type: string ResetPasswordRequest: type: object properties: token: type: string minLength: 1 newPassword: type: string maxLength: 200 minLength: 8 required: - newPassword - token ForgotPasswordRequest: type: object properties: email: type: string minLength: 1 required: - email MfaVerifyRequest: type: object properties: pendingToken: type: string minLength: 1 code: type: string minLength: 1 audience: type: string device: $ref: '#/components/schemas/DeviceInfo' required: - code - pendingToken LogoutRequest: type: object properties: refreshToken: type: string minLength: 1 required: - refreshToken LoginRequest: type: object properties: email: type: string minLength: 1 password: type: string minLength: 1 audience: type: string device: $ref: '#/components/schemas/DeviceInfo' required: - email - password CreateApplicationRequest: type: object properties: organizationId: type: integer format: int64 identifier: type: string minLength: 1 name: type: string minLength: 1 webRefreshTtlDays: type: integer format: int32 maximum: 180 minimum: 1 deviceRefreshTtlDays: type: integer format: int32 maximum: 180 minimum: 1 required: - identifier - name - organizationId CreatePermissionRequest: type: object properties: code: type: string minLength: 1 description: type: string required: - code PermissionResponse: type: object properties: id: type: integer format: int64 applicationId: type: integer format: int64 code: type: string description: type: string UsageResponse: type: object properties: applications: type: integer format: int64 RoleRef: type: object properties: id: type: integer format: int64 name: type: string UserSummary: type: object properties: id: type: integer format: int64 email: type: string fullName: type: string status: type: string hasPassword: type: boolean organizationId: type: integer format: int64 roles: type: array items: $ref: '#/components/schemas/RoleRef' DeviceView: type: object properties: deviceId: type: string name: type: string platform: type: string lastSeenAt: type: string format: date-time createdAt: type: string format: date-time VisibleOrgsResponse: type: object properties: parentOrgId: type: integer format: int64 childOrgIds: type: array items: type: integer format: int64 nextCursor: type: string hasNext: type: boolean SandboxSummary: type: object properties: tenantId: type: integer format: int64 name: type: string slug: type: string expiresAt: type: string format: date-time CursorSliceOrganization: type: object properties: items: type: array items: $ref: '#/components/schemas/Organization' nextCursor: type: string hasNext: type: boolean JobSummary: type: object properties: id: type: integer format: int64 tenantId: type: integer format: int64 rootOrgId: type: integer format: int64 status: type: string dryRun: type: boolean counts: type: object additionalProperties: $ref: '#/components/schemas/Counts' errors: type: array items: $ref: '#/components/schemas/Error' createdAt: type: string format: date-time completedAt: type: string format: date-time ClientSummary: type: object properties: clientId: type: string name: type: string scopes: type: array items: type: string applicationId: type: integer format: int64 AuditEntry: type: object properties: id: type: integer format: int64 action: type: string userId: type: integer format: int64 organizationId: type: integer format: int64 createdAt: type: string format: date-time ipAddress: type: string metadata: type: object additionalProperties: {} QuotaResponse: type: object properties: used: type: integer format: int64 limit: type: integer format: int32 securitySchemes: bearerAuth: type: http description: >- A MANAGEMENT access token — call POST /api/auth/login with the `audience` field OMITTED. Permissions are audience-scoped: a token minted for one of your applications carries only that app's codes, so it has NO system permissions (ORG_MANAGE, USER_MANAGE, …) and the /api/** endpoints below will answer 403 no matter what roles the user holds. Omit `audience` to get a token whose `aud` is this service and which carries the caller's system permissions. scheme: bearer bearerFormat: JWT clientBasicAuth: type: http description: >- HTTP Basic with clientId as username and the client secret as password — used only at POST /oauth2/token. scheme: basic clientCredentials: type: oauth2 description: >- Machine-to-machine. Swagger UI can fetch a token here and use it against the resource endpoints. flows: clientCredentials: tokenUrl: http://localhost:9900/oauth2/token scopes: api.default: Default machine scope reports.read: Read reports (example)