openapi: 3.0.2 info: title: Phase Two Admin REST API description: | This is a REST API reference for the Phase Two Keycloak custom resources. These are extensions to the standard [Keycloak Admin REST API](https://www.keycloak.org/docs-api/17.0/rest-api/index.html). ### Base URI format Paths specified in the documentation are relative to the the base URI. - Format: `https://:/auth/realms` - Example: `https://app.phasetwo.io/auth/realms` ### Authentication Authentication is achieved by using the `Authentication: Bearer ` header in all requests. This is either the access token received from a normal authentication, or by a request directly to the OpenID Connect token endpoint. It is recommended that you use a Keycloak Admin Client, such as [this one for Javascript](https://github.com/keycloak/keycloak-nodejs-admin-client), as they take care of authentication, getting an access token, and refreshing it when it expires. #### Client credentials grant example ``` POST /auth/realms/test-realm/protocol/openid-connect/token Host: app.phasetwo.io Accept: application/json Content-type: application/x-www-form-urlencoded grant_type=client_credentials&client_id=admin-cli&client_secret=fd649804-3a74-4d69-acaa-8f065c6b7da1 ``` #### Password grant example ``` POST /auth/realms/test-realm/protocol/openid-connect/token Host: app.phasetwo.io Accept: application/json Content-type: application/x-www-form-urlencoded grant_type=password&username=uname@foo.com&password=pwd123AZY&client_id=admin-cli ``` ### SDKs Modern API libraries are available for several common languages. These are available as open source at the links below, or you can choose to generate your own using our [OpenAPI spec file](https://raw.githubusercontent.com/p2-inc/phasetwo-docs/master/openapi.yaml). | Language | Library | | --- | --- | | Java (and other JVM langs) | https://github.com/p2-inc/phasetwo-java | | JavaScript/TypeScript | https://github.com/p2-inc/phasetwo-js | | Python | https://github.com/p2-inc/phasetwo-python | version: "v1" servers: - url: "{protocol}://{host}{port}{relativePath}/realms" variables: host: enum: - app.phasetwo.io - localhost default: app.phasetwo.io description: API host port: enum: - "" - "8081" default: "" description: API port relativePath: enum: - "" - "/auth" default: "" description: Relative path protocol: enum: - http - https default: https components: securitySchemes: access_token: type: http scheme: bearer bearerFormat: "" schemas: MyOrganizationsRepresentation: type: object additionalProperties: $ref: "#/components/schemas/MyOrganizationRepresentation" MyOrganizationRepresentation: type: object properties: name: type: string displayName: type: string url: type: string attributes: type: object additionalProperties: type: array items: type: string roles: type: array items: type: string IdentityProviderRepresentation: type: object properties: addReadTokenRoleOnCreate: type: boolean alias: type: string config: type: object additionalProperties: true displayName: type: string enabled: type: boolean firstBrokerLoginFlowAlias: type: string internalId: type: string linkOnly: type: boolean postBrokerLoginFlowAlias: type: string providerId: type: string storeToken: type: boolean trustEmail: type: boolean IdentityProviderMapperRepresentation: type: object properties: config: type: object additionalProperties: true id: type: string identityProviderAlias: type: string identityProviderMapper: type: string name: type: string RealmAttributeRepresentation: type: object properties: name: type: string value: type: string realm: type: string KeyedRealmAttributeRepresentation: type: object additionalProperties: $ref: "#/components/schemas/RealmAttributeRepresentation" OrganizationRepresentation: type: object properties: id: type: string name: type: string displayName: type: string url: type: string realm: type: string domains: type: array items: type: string attributes: type: object additionalProperties: type: array items: type: string OrganizationDomainRepresentation: type: object properties: domain_name: type: string verified: type: boolean record_key: type: string record_value: type: string type: type: string OrganizationRoleRepresentation: type: object properties: id: type: string name: type: string description: type: string PortalLinkRepresentation: type: object properties: user: type: string link: type: string redirect: type: string InvitationRequestRepresentation: type: object properties: email: type: string send: type: boolean inviterId: type: string redirectUri: type: string roles: type: array items: type: string InvitationRepresentation: type: object properties: id: type: string email: type: string inviterId: type: string organizationId: type: string roles: type: array items: type: string UserRepresentation: type: object properties: attributes: type: object additionalProperties: true createdTimestamp: type: integer format: int64 email: type: string emailVerified: type: boolean enabled: type: boolean firstName: type: string groups: type: array items: type: string id: type: string lastName: type: string username: type: string AuthDetailsRepresentation: type: object properties: realmId: type: string clientId: type: string userId: type: string ipAddress: type: string username: type: string sessionId: type: string EventRepresentation: type: object properties: uid: type: string time: type: integer realmId: type: string organizationId: type: string type: type: string representation: type: string operationType: type: string resourcePath: type: string resourceType: type: string error: type: string authDetails: $ref: "#/components/schemas/AuthDetailsRepresentation" details: type: object additionalProperties: true WebhookRepresentation: type: object properties: attributes: type: object id: type: string enabled: type: boolean url: type: string secret: type: string createdBy: type: string createdAt: type: string realm: type: string eventTypes: type: array items: type: string MagicLinkRepresentation: type: object properties: email: type: string client_id: type: string redirect_uri: type: string expiration_seconds: type: integer force_create: type: boolean send_email: type: boolean required: - email - client_id - redirect_uri security: - access_token: [] externalDocs: description: Public documentation url: https://phasetwo.io/docs paths: # organization resources /{realm}/orgs: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple get: tags: - Organizations summary: Get organizations description: Get a paginated list of organizations using optional search query parameters. operationId: getOrganizations parameters: - in: query name: search schema: type: string style: form description: search by name - in: query name: first schema: type: integer format: int32 style: form - in: query name: max schema: type: integer format: int32 style: form - in: query name: q schema: type: string style: form description: search by attributes using the format `k1:v1,k2:v2` responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/OrganizationRepresentation" post: tags: - Organizations summary: Create a new organization operationId: createOrganization requestBody: content: application/json: schema: $ref: "#/components/schemas/OrganizationRepresentation" required: true responses: 201: description: success headers: Location: schema: type: string description: URI indicating the ID of the new resource. /{realm}/orgs/count: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple get: tags: - Organizations summary: Get organizations count description: Get a count of organizations using an optional search query. operationId: getOrganizationsCount parameters: - in: query name: search schema: type: string style: form responses: 200: description: success content: application/json: schema: type: integer format: int32 /{realm}/orgs/me: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple get: tags: - Organizations summary: Get orgs and roles for authenticated user description: Get a list of all organizations that the user is a member and their roles in those organizations. Similar idea to /userinfo in OIDC. operationId: getMe responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/MyOrganizationsRepresentation" /{realm}/orgs/{orgId}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple get: tags: - Organizations summary: Get organization by id operationId: getOrganizationById responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/OrganizationRepresentation" put: tags: - Organizations summary: Update this organization by id operationId: updateOrganization requestBody: content: application/json: schema: $ref: "#/components/schemas/OrganizationRepresentation" required: true responses: 204: description: success delete: tags: - Organizations summary: Delete the organization operationId: deleteOrganization responses: 204: description: success /{realm}/orgs/{orgId}/portal-link: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple post: tags: - Organizations summary: Create a link for the organization's admin portal operationId: createPortalLink description: Create a link for this organizations admin portal. This link encodes an action token on behalf of the organization's default admin user, or the user that is optionally specified in this request. The user specified must be a member of this organization, and have full organization admin roles. requestBody: content: application/x-www-form-urlencoded: schema: type: object properties: userId: type: string responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/PortalLinkRepresentation" # organization membership resources /{realm}/orgs/{orgId}/members: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple get: tags: - Organization Memberships summary: Get organization memberships operationId: getOrganizationMemberships description: Get a paginated list of users who are a member of the specified organization. parameters: - in: query name: search schema: type: string style: form - in: query name: first schema: type: integer format: int32 style: form - in: query name: max schema: type: integer format: int32 style: form responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/UserRepresentation" # organization membership resources /{realm}/orgs/{orgId}/members/count: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple get: tags: - Organization Memberships summary: Get organization members count operationId: getOrganizationMembershipsCount description: Get total number of members of a given organization responses: 200: description: success content: application/json: schema: type: integer format: int32 /{realm}/orgs/{orgId}/domains: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple get: tags: - Organization Domains summary: Get details for all domains owned by an organization operationId: getOrganizationDomains responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/OrganizationDomainRepresentation" /{realm}/orgs/{orgId}/domains/{domainName}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: domainName description: domain name required: true schema: type: string style: simple get: tags: - Organization Domains summary: Get details for a domain owned by an organization operationId: getOrganizationDomain responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/OrganizationDomainRepresentation" /{realm}/orgs/{orgId}/domains/{domainName}/verify: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: domainName description: domain name required: true schema: type: string style: simple post: tags: - Organization Domains summary: Start domain verification operationId: verifyDomain description: Initiate a verification check for the domain name owned by this organization responses: 202: description: success /{realm}/orgs/{orgId}/members/{userId}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: userId description: user id required: true schema: type: string style: simple get: tags: - Organization Memberships summary: Check if a user is a member of an organization operationId: checkOrganizationMembership responses: 204: description: success put: tags: - Organization Memberships summary: Add an organization member operationId: addOrganizationMember description: Add the specified user to the specified organization as a member responses: 201: description: success delete: tags: - Organization Memberships summary: Remove an organization member operationId: removeOrganizationMember description: Remove the specified user from the specified organization as a member responses: 204: description: success # organization invitation resources /{realm}/orgs/{orgId}/invitations: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple post: tags: - Organization Invitations summary: Create an invitation to an organization operationId: addOrganizationInvitation requestBody: content: application/json: schema: $ref: "#/components/schemas/InvitationRequestRepresentation" required: true responses: 201: description: success 409: description: invitation already exists get: tags: - Organization Invitations summary: Get organization invitations operationId: getOrganizationInvitations description: Get a paginated list of invitations to an organization, using an optional search query for email address. parameters: - in: query name: search schema: type: string style: form - in: query name: first schema: type: integer format: int32 style: form - in: query name: max schema: type: integer format: int32 style: form responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/InvitationRepresentation" /{realm}/orgs/{orgId}/invitations/{invitationId}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: invitationId description: invitation id required: true schema: type: string style: simple delete: tags: - Organization Invitations summary: Remove a pending invitation operationId: removeOrganizationInvitation responses: 204: description: success /{realm}/orgs/{orgId}/roles: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple get: tags: - Organization Roles summary: Get roles for this organization operationId: getOrganizationRoles responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/OrganizationRoleRepresentation" post: tags: - Organization Roles summary: Create a new role for this organization operationId: createOrganizationRole requestBody: content: application/json: schema: $ref: "#/components/schemas/OrganizationRoleRepresentation" required: true responses: 201: description: success /{realm}/orgs/{orgId}/roles/{name}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: name description: organization role name required: true schema: type: string style: simple get: tags: - Organization Roles summary: Get role for this organization by name operationId: getOrganizationRole responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/OrganizationRoleRepresentation" put: tags: - Organization Roles summary: Update role for this organization operationId: updateOrganizationRole requestBody: content: application/json: schema: $ref: "#/components/schemas/OrganizationRoleRepresentation" required: true responses: 204: description: success delete: tags: - Organization Roles summary: Delete this organization role operationId: deleteOrganizationRole responses: 204: description: success /{realm}/orgs/{orgId}/roles/{name}/users: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: name description: organization role name required: true schema: type: string style: simple get: tags: - Organization Roles summary: Get users with this organization role operationId: getUserOrganizationRoles responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/UserRepresentation" /{realm}/orgs/{orgId}/roles/{name}/users/{userId}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: name description: organization role name required: true schema: type: string style: simple - in: path name: userId description: user id required: true schema: type: string style: simple get: tags: - Organization Roles summary: Check if a user has an organization role operationId: checkUserOrganizationRole responses: 204: description: success put: tags: - Organization Roles summary: Grant a user an organization role operationId: grantUserOrganizationRole description: Grant the specified user to the specified organization role responses: 201: description: success delete: tags: - Organization Roles summary: Revoke an organization role from a user operationId: revokeUserOrganizationRole description: Revoke the specified organization role from the specified user responses: 204: description: success # identity provider resources /{realm}/orgs/{orgId}/idps/import-config: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple post: tags: - Identity Providers summary: Import identity provider from uploaded JSON file operationId: importIdpJson responses: 200: description: success content: application/json: schema: type: object additionalProperties: true /{realm}/orgs/{orgId}/idps: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple get: tags: - Identity Providers summary: Get identity providers for this organization operationId: getIdps responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/IdentityProviderRepresentation" post: tags: - Identity Providers summary: Create a new identity provider for this organization operationId: createIdp requestBody: description: JSON body content: application/json: schema: $ref: "#/components/schemas/IdentityProviderRepresentation" required: true responses: 201: description: success /{realm}/orgs/{orgId}/idps/{alias}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: alias description: Identity Provider alias required: true schema: type: string style: simple get: tags: - Identity Providers summary: Get identity provider for this organization by alias operationId: getIdp responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/IdentityProviderRepresentation" put: tags: - Identity Providers summary: Update identity provider for this organization by alias operationId: updateIdp requestBody: content: application/json: schema: $ref: "#/components/schemas/IdentityProviderRepresentation" required: true responses: 200: description: success delete: tags: - Identity Providers summary: Delete the identity provider operationId: deleteIdp responses: 204: description: success # identity provider mapper resources /{realm}/orgs/{orgId}/idps/{alias}/mappers: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: alias required: true schema: type: string style: simple get: tags: - Identity Providers summary: Get mappers for identity provider operationId: getIdpMappers responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/IdentityProviderMapperRepresentation" post: tags: - Identity Providers summary: Add a mapper to identity provider operationId: addIdpMapper requestBody: content: application/json: schema: $ref: "#/components/schemas/IdentityProviderMapperRepresentation" required: true responses: 201: description: success /{realm}/orgs/{orgId}/idps/{alias}/mappers/{id}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple - in: path name: alias required: true schema: type: string style: simple - in: path name: id description: Mapper id required: true schema: type: string style: simple get: tags: - Identity Providers summary: Get mapper by id for the identity provider operationId: getIdpMapper responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/IdentityProviderMapperRepresentation" put: tags: - Identity Providers summary: Update a mapper for the identity provider operationId: updateIdpMapper requestBody: content: application/json: schema: $ref: "#/components/schemas/IdentityProviderMapperRepresentation" required: true responses: 200: description: success delete: tags: - Identity Providers summary: Delete a mapper for the identity provider operationId: deleteIdpMapper responses: 204: description: success /{realm}/users/{userId}/orgs: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: userId description: user id required: true schema: type: string style: simple get: tags: - Users summary: List organizations for the given user responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/OrganizationRepresentation" /{realm}/users/{userId}/orgs/{orgId}/roles: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: userId description: user id required: true schema: type: string style: simple - in: path name: orgId description: organization id required: true schema: type: string style: simple get: tags: - Users summary: List organization roles for the given user and org responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/OrganizationRoleRepresentation" /{realm}/events: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple post: tags: - Events summary: Create a new audit log event operationId: createEvent requestBody: description: JSON body content: application/json: schema: $ref: "#/components/schemas/EventRepresentation" required: true responses: 202: description: Event received 400: description: Malformed event 403: description: Rate limit exceeded 409: description: Reserved event type /{realm}/attributes: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple get: tags: - Attributes summary: Get realm attributes description: Get a list of attributes for this realm operationId: getRealmAttributes responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/KeyedRealmAttributeRepresentation" post: tags: - Attributes summary: Create a new realm attribute operationId: createRealmAttribute requestBody: description: JSON body content: application/json: schema: $ref: "#/components/schemas/RealmAttributeRepresentation" required: true responses: 201: description: Attribute created 400: description: Malformed attribute /{realm}/attributes/{attributeKey}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: attributeKey description: attribute key required: true schema: type: string style: simple get: tags: - Attributes summary: Get realm attribute by key operationId: getRealmAttributeByKey responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/RealmAttributeRepresentation" 404: description: Realm attribute doesn't exist put: tags: - Attributes summary: Update realm attribute by key operationId: updateRealmAttributeByKey requestBody: content: application/json: schema: $ref: "#/components/schemas/RealmAttributeRepresentation" required: true responses: 204: description: success 404: description: Realm attribute doesn't exist delete: tags: - Attributes summary: Delete the realm attribute operationId: deleteRealmAttribute responses: 204: description: success 404: description: Realm attribute doesn't exist /{realm}/webhooks: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple get: tags: - Events summary: Get webhooks description: Get a list of webhooks for this realm operationId: getWebhooks responses: 200: description: success content: application/json: schema: type: array items: $ref: "#/components/schemas/WebhookRepresentation" post: tags: - Events summary: Create a new webhook operationId: createWebhook requestBody: description: JSON body content: application/json: schema: $ref: "#/components/schemas/WebhookRepresentation" required: true responses: 201: description: Webhook created 400: description: Malformed webhook /{realm}/webhooks/{webhookId}: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple - in: path name: webhookId description: webhook id required: true schema: type: string style: simple get: tags: - Events summary: Get webhook by id operationId: getWebhookById responses: 200: description: success content: application/json: schema: $ref: "#/components/schemas/WebhookRepresentation" 404: description: Webhook doesn't exist put: tags: - Events summary: Update this webhook by id operationId: updateWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/WebhookRepresentation" required: true responses: 204: description: success 404: description: Webhook doesn't exist delete: tags: - Events summary: Delete the webhook operationId: deleteWebhook responses: 204: description: success 404: description: Webhook doesn't exist /{realm}/magic-link: parameters: - in: path name: realm description: realm name (not id!) required: true schema: type: string style: simple post: tags: - Users summary: Create a magic link to log in a user operationId: createMagicLink requestBody: description: JSON body content: application/json: schema: $ref: "#/components/schemas/MagicLinkRepresentation" required: true responses: 200: description: Magic Link created 400: description: Malformed request 404: description: User or Client not found