# User & Role Management

## Overview

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](https://docs.panther.com/~/changes/15ann7vKLltCCAGHtdQr/panther-developer-workflows/api/..#step-1-choose-a-method-for-invoking-the-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.&#x20;

Note: The `createdAt` field is in ISO 8601 date and time standard.

#### Listing Users

```graphql
query users {
  users {
    id
    givenName
    familyName
    email
    status
    createdAt
    lastLoggedInAt
    role {
      name
      id
      permissions
    }
  }
}
```

#### Retrieving a User

{% tabs %}
{% tab title="User by Email Address" %}

```graphql
query user {
  userByEmail(email: "example@domain.com") {
    id
    givenName
    familyName
    email
    role {
      name
      id
      permissions
    }
    status
    createdAt
  }
}
```

{% endtab %}

{% tab title="User by ID" %}

```graphql
query user {
  userById(id: "8h81hfh-ij828db") {
    id
    givenName
    familyName
    email
    role {
      name
      id
      permissions
    }
    status
    createdAt
  }
}
```

{% endtab %}
{% endtabs %}

#### Inviting a new User

```graphql
mutation inviteUser {
    inviteUser(input: {
        email: "example@domain.com"
        givenName: "firstname"
        familyName: "lastname"
        role: {
            kind: NAME
            value: "Analyst"
        }
    })
    {
        user {
            id
            status
        }
    }
  }
```

#### Updating a User

```graphql
mutation updateUser {
    updateUser(input: {
        id: "8h81hfh-ij828db"
        familyName: "newName"
    })
    {
        user {
            email
            givenName
            familyName
        }
    }
}
```

#### Deleting a User

```graphql
mutation deleteUser{
  deleteUser(input: {
    id: "8h81hfh-ij828db"
  })
  {
    id # the delete operation doesn't return a `user` object; just an ID
  }
}
```

#### Listing Roles

```graphql
query roles {
  roles( 
    # This input is optional. Without input, the query will return all roles.
    input: {
      nameContains: "admin",
      sortDir: ascending
    }) 
  {
    createdAt
    id
    name
    permissions
    updatedAt
    updatedBy {
      ... on User {
        email
        id
      }
      ... on APIToken {
        id
        name
      }
    }
    # Used only if RBAC per log type is enabled
    logTypeAccess 
    logTypeAccessKind
  }
}
```

#### Retrieving a Role

{% tabs %}
{% tab title="Role by Name" %}

```graphql
query adminRole {
  roleByName(
   name: "admin"
   ) {
    createdAt
    id
    name
    permissions
    updatedAt
    updatedBy {
      ... on User {
        email
        id
      }
      ... on APIToken {
        id
        name
      }
    }
    # Used only if RBAC per log type is enabled
    logTypeAccess 
    logTypeAccessKind
  }
}
```

{% endtab %}

{% tab title="Role by ID" %}

```graphql
query adminRole {
  roleById(
   id: "feeafade-c545"
   ) {
    createdAt
    id
    logTypeAccess
    logTypeAccessKind
    name
    permissions
    updatedAt
    updatedBy {
      ... on User {
        email
        id
      }
      ... on APIToken {
        id
        name
      }
    }
    # Used only if RBAC per log type is enabled
    logTypeAccess 
    logTypeAccessKind
  }
}
```

{% endtab %}
{% endtabs %}

#### Creating a new Role

{% hint style="warning" %}
**Note:** The permission `UserModify` provides full admin access to the Panther platform. Use discretion when assigning this permission to new roles.
{% endhint %}

{% tabs %}
{% tab title="Basic" %}

```graphql
mutation createRole {
  createRole(input: {
    name: "new-role"
    permissions: [
      UserRead
      AlertRead
    ]
  })
  {  
    role {
      name
      id
      permissions
    }
  }
}
```

{% endtab %}

{% tab title="RBAC per log type enabled" %}

```graphql
mutation createRole {
  createRole(input: {
    name: "new-role"
    permissions: [
      UserRead
      AlertRead
    ]
    # Used only if the RBAC per log type feature is enabled
    logTypeAccess:["AWS.ALB"]
    logTypeAccessKind: ALLOW
  })
  {  
    role {
      name
      id
      permissions
      logTypeAccess
      logTypeAccessKind
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Updating a Role

{% hint style="warning" %}
**Note:** The permissions in the updateRole input must contain **all** desired permissions for the role.
{% endhint %}

{% tabs %}
{% tab title="Basic" %}

```graphql
mutation updateRole {
  updateRole(input: {
    id: "fea8sje-92jdnhc"
    name: "updated-role-name"
    permissions: [
      UserRead
      AlertRead
      AlertModify
    ]
  })
  {
    role {
      name
      id
      permissions
    }
  }
}
```

{% endtab %}

{% tab title="RBAC per log type enabled" %}

```graphql
mutation updateRole {
  updateRole(input: {
    id: "fea8sje-92jdnhc"
    name: "updated-role-name"
    permissions: [
      UserRead
      AlertRead
      AlertModify
    ]
    # Used only if the RBAC per log type feature is enabled
    logTypeAccess:["AWS.ALB"]
    logTypeAccessKind: DENY
  })
  {
    role {
      name
      id
      permissions
      logTypeAccess 
      logTypeAccessKind
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### Deleting a Role

```graphql
mutation deleteRole {
  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](#common-operations) examples to showcase an end-to-end flow.

#### **Create a new user administrator role and invite a user to that role.**

{% tabs %}
{% tab title="Python" %}

```python
# pip install gql aiohttp

from gql import gql, Client
from gql.transport.aiohttp import AIOHTTPTransport

transport = 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": "newAdmin@domain.local",
      "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"]}.'
```

{% endtab %}

{% tab title="NodeJS" %}

```javascript
import { GraphQLClient, gql } from "graphql-request";

const client = new GraphQLClient(
  "YOUR_PANTHER_API_URL",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);

// `createUserAdmin` is a nickname for the query. You can fully omit it.
const createUserAdmin = 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.
const inviteUser = gql`
  mutation inviteUser($input: InviteUserInput!) {
    inviteUser(input: $input) {
      user {
        id
        email
      }
    }
  }
`;

(async () => {
  try {
    const newRoleData = await client.request(createUserAdmin);

    const inviteUserOutput = await client.request(inviteUser, {
      input: {
        email: "newAdmin@domain.local",
        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);
  }
})();

```

{% endtab %}
{% endtabs %}
