The Panther API supports the following user and role operations:
List users
Get a user by ID or by email address
Invite new users
Update a user's information and role
Delete users
List roles
Get a role by ID or by name
Create a new role
Update a role's information and permissions
Delete roles
You can invoke Panther's API by using your Console's API Playground, or the GraphQL-over-HTTP API. Learn more about these methods on Panther API.
See the sections below for GraphQL queries, mutations, and end-to-end workflow examples around core user and role management operations.
Common user and role management operations
Below are some of the most common GraphQL user and role management operations in Panther. These examples demonstrate the documents you have to send using a GraphQL client (or curl) to make a call to Panther's GraphQL API.
Note: The createdAt field is in ISO 8601 date and time standard.
Listing Users
queryusers { users { id givenName familyName email status createdAt lastLoggedInAt role { name id permissions } }}
Retrieving a User
queryuser { userByEmail(email: "[email protected]") { id givenName familyName email role { name id permissions } status createdAt }}
queryuser { userById(id: "8h81hfh-ij828db") { id givenName familyName email role { name id permissions } status createdAt }}
Inviting a new User
mutationinviteUser { inviteUser(input: {email: "[email protected]"givenName: "firstname"familyName: "lastname"role: {kind: NAMEvalue: "Analyst" } }) { user { id status } } }
mutationdeleteUser{ deleteUser(input: {id: "8h81hfh-ij828db" }) { id # the delete operation doesn't return a `user` object; just an ID }}
Listing Roles
queryroles { roles( # This input is optional. Without input, the query will return all roles. input: {nameContains: "admin",sortDir: ascending }) { createdAt id name permissions updatedAt updatedBy {...onUser { email id }...onAPIToken { id name } } # Used only if RBAC per log type is enabled logTypeAccess logTypeAccessKind }}
Retrieving a Role
queryadminRole { roleByName( name: "admin" ) { createdAt id name permissions updatedAt updatedBy {...onUser { email id }...onAPIToken { id name } } # Used only if RBAC per log type is enabled logTypeAccess logTypeAccessKind }}
queryadminRole { roleById( id: "feeafade-c545" ) { createdAt id logTypeAccess logTypeAccessKind name permissions updatedAt updatedBy {...onUser { email id }...onAPIToken { id name } } # Used only if RBAC per log type is enabled logTypeAccess logTypeAccessKind }}
Creating a new Role
Note: The permission UserModify provides full admin access to the Panther platform. Use discretion when assigning this permission to new roles.
mutationcreateRole { createRole(input: {name: "new-role"permissions: [ UserRead AlertRead ] }) { role { name id permissions } }}
mutationcreateRole { createRole(input: {name: "new-role"permissions: [ UserRead AlertRead ] # Used only if the RBAC per log type feature is enabledlogTypeAccess:["AWS.ALB"]logTypeAccessKind: ALLOW }) { role { name id permissions logTypeAccess logTypeAccessKind } }}
Updating a Role
Note: The permissions in the updateRole input must contain all desired permissions for the role.
mutationupdateRole { updateRole(input: {id: "fea8sje-92jdnhc"name: "updated-role-name"permissions: [ UserRead AlertRead AlertModify ] }) { role { name id permissions } }}
mutationupdateRole { updateRole(input: {id: "fea8sje-92jdnhc"name: "updated-role-name"permissions: [ UserRead AlertRead AlertModify ] # Used only if the RBAC per log type feature is enabledlogTypeAccess:["AWS.ALB"]logTypeAccessKind: DENY }) { role { name id permissions logTypeAccess logTypeAccessKind } }}
Deleting a Role
mutationdeleteRole { deleteRole(input: {id: "e146c8d8-c6a5" }) { id # The delete operation doesn't return a `role` object. Just an ID. }}
End-to-end examples
Below, we will build on the Common Operations examples to showcase an end-to-end flow.
Create a new user administrator role and invite a user to that role.
# pip install gql aiohttpfrom gql import gql, Clientfrom gql.transport.aiohttp import AIOHTTPTransporttransport =AIOHTTPTransport( url="YOUR_PANTHER_API_URL", headers={"X-API-Key": "YOUR_API_KEY"},)client =Client(transport=transport, fetch_schema_from_transport=True)create_user_admin =gql(""" mutation newAdminRole { createRole (input: { name: "user-admin" permissions: [ UserRead UserModify OrganizationAPITokenRead GeneralSettingsRead ] }) { role { name id } } } """)invite_user =gql(""" mutation inviteUser($input: InviteUserInput!) { inviteUser (input: $input) { user { id email } } } """)new_role_data = client.execute( create_user_admin)print(f'new role ID is {new_role_data["createRole"]["role"]["id"]}')response_data = client.execute( invite_user, variable_values= {"input": {"email": "[email protected]","givenName": "user","familyName": "admin","role": {"kind": "ID","value": new_role_data["createRole"]["role"]["id"], } } })print(f'Successfully invited user {response_data["inviteUser"]["user"]["email"]} with role {new_role_data["createRole"]["role"]["name"]}.'
import { GraphQLClient, gql } from"graphql-request";constclient=newGraphQLClient("YOUR_PANTHER_API_URL", { headers: { "X-API-Key":"YOUR_API_KEY" } });// `createUserAdmin` is a nickname for the query. You can fully omit it.constcreateUserAdmin=gql` mutation newAdminRole { createRole( input: { name: "user-admin" permissions: [ UserRead UserModify OrganizationAPITokenRead GeneralSettingsRead ] } ) { role { name id } } }`;// `inviteUser` is a nickname for the mutation. You can fully omit it.constinviteUser=gql` mutation inviteUser($input: InviteUserInput!) { inviteUser(input: $input) { user { id email } } }`;(async () => {try {constnewRoleData=awaitclient.request(createUserAdmin);constinviteUserOutput=awaitclient.request(inviteUser, { input: { email:"[email protected]", givenName:"user", familyName:"admin", role: { kind:"ID", value:newRoleData.createRole.role.id } } });console.log( `Successfully invited user ${inviteUserOutput.inviteUser.user.email} with role ${newRoleData.createRole.role.name}.`
); } catch (err) {console.error(err); }})();