# Manage Identity

> How to set up Identity to sign in and use the Python SDK.

Unity Cloud services require the caller to be properly authorized before you can perform any operation or access other modules such as Assets.

There are two modules available to retrieve such authorization:

* `unity_cloud.identity.user_login`
* `unity_cloud.identity.service_account`

Only one module can be used at all time. Declaring `unity_cloud.identity.user_login.use()` prevents any call to the `unity_cloud.identity.service_account` module by throwing an exception.

## How do I...?

### Authenticate with a user login

The user sign-in process requires to:

1. Manually request a sign-in (or a sign-out) from the integration.
2. Enter your Unity account credentials to authenticate.

The user login implements the [OAuth 2.0 PKCE](https://oauth.net/2/pkce/) standard flow to retrieve an access token, and relies on the default OS browser as an intermediary to authenticate.

#### Initialize and sign in to the Unity Dashboard ##signin

To use standard user login, follow these steps:

1. Call `unity_cloud.identity.user_login.use()` to initialize the `user_login` module. This action automatically checks if any refresh token is currently cached. If so, you are authenticated.
2. If there is no token, call `login` to trigger your browser to open and sign in to Unity Dashboard.

> **Note:**
>
> `unity_cloud.identity.user_login.use()` also gives access to the other methods in the `user_login` module: `login`, `logout`, `get_user_infos`, and `get_authentication_state`.

After you have signed in, a refresh token is automatically cached.

```python
def initialize_user_login():
    unity_cloud.initialize()
    unity_cloud.identity.user_login.use()

    auth_state = unity_cloud.identity.user_login.get_authentication_state()
    if auth_state != unity_cloud.identity.user_login.Authentication_State.LOGGED_IN:
        unity_cloud.identity.user_login.login()
```

> **Note:**
>
> Calling `login` when the user is already considered signed in will generate an exception. To prevent this, you can validate the user's authentication state by calling `get_authentication_state`. \* When using the `user_login` module, calls to the `service_account` module will return invalid operation exceptions. These modules are mutually exclusive.

#### Sign out

To sign out, follow these steps:

1. Initialize the following modules in this order:
   1. `unity_cloud`
   2. `unity_cloud.identity.user_login.use()`
   3. (Optional) `unity_cloud.identity.user_login.login`. Read more about [initializing and signing in the user through Unity Dashboard](#signin).
2. Call the `logout` method with the `clear_cache` argument set to `TRUE`. \
   Calling the method signs you out from the browser.
3. (Optional) Set the `clear_cache` argument to `FALSE` to allow automatic re-login next time `unity_cloud.identity.user_login.use()` is called.

```python
    unity_cloud.identity.user_login.logout(
      clear_cache = True
    )
```

#### Get information about the current user

To retrieve all information on the current user, including their access token, call the `get_current_user_info` method.

```python
    user_infos = unity_cloud.identity.user_login.get_current_user_info()
```

#### Use a callback to track the authentication state during a user sign-in

Subscribing to the authentication state change allows you to get a callback every step of the authentication flow.

The states tracked are: `AWAITING_INITIALIZATION`, `AWAITING_LOGIN`, `LOGGED_IN`, `AWAITING_LOGOUT`, and `LOGGED_OUT`.

```python
  def auth_state_callback(state):
      print(state)

    unity_cloud.identity.user_login.subscribe(
      event_type = unity_cloud.identity.user_login.AUTHENTICATION_STATE_CHANGED_EVENT,
      callback = auth_state_callback
    )
    unity_cloud.identity.user_login.login()
    unity_cloud.identity.user_login.logout(clear_cache = True)
    unity_cloud.identity.user_login.unsubscribe(
      event_type = unity_cloud.identity.user_login.AUTHENTICATION_STATE_CHANGED_EVENT,
      callback = auth_state_callback
    )
```

### Use a service account to perform app-oriented authorization

The service account allows authorization for internal headless scenarios (automated scripts, tests, etc.).

#### Generate a service account

1. [Create a service account](https://services.docs.unity.com/docs/service-account-auth/#create-a-service-account).
2. Make sure to store the service account credentials (`key ID` and `secret key`) in a secure and private location. \
   Refer to these credentials in your integration to authorize your calls to Unity Cloud services.
3. Attach the service account to an organization or a project.

#### Set up your app to use a service account

After the required `unity_cloud` initialization, pass the `key id` and `secret key` of your service account generated via the Dashboard.

> **Note:**
>
> When using the `service_account` module, calls to the `user_login` module will return invalid operation exceptions. These modules are mutually exclusive.

```python
    key_id = "1234abcd-ab12-cd34-ef56-123456abcdef"
    key = "12345678ABCDefgh-1234AbC-5678eFg"
    unity_cloud.identity.service_account.use(key_id=key_id, key=key)
```

### Get a list of the accessible organizations or projects

To get a list of accessible organizations or projects, follow these steps:

1. Use the `get_organization_list` method to retrieve a list of all accessible organizations.
2. Call `get_project_list` with an organization id to retrieve the accessible projects contained in it.
   * (Optional) Add the parameter `limit_to` to limit the amount of returned results. Leave it untouched or set it to 0 to return everything.
   * (Optional) Add the parameter `skip` to specify the number of collection to skip in the results. Use it in combination with limit\_to to page through results.

```python
    orgs = unity_cloud.identity.get_organization_list()
    if len(orgs) != 0:
        projects = unity_cloud.identity.get_project_list(orgs[0].id)
        permissions = unity_cloud.identity.get_organization_permissions(orgs[0].id)
        roles = unity_cloud.identity.get_organization_roles(orgs[0].id)
```

The `get_organization_permissions`, `get_organization_roles`, `get_project_permission` and `get_project_roles` methods provide more granular information about roles and permissions that are inherited from whichever authorization flow you chose.

### Create a project

To create a project, follow these steps:

1. Create a `ProjectCreation` object with the name of the new project and optionally metadata.
2. Call `create_project` with the `ProjectCreation` object and the organization ID.

```python
project_creation = ProjectCreation(name="myNewProject")
unity_cloud.identity.create_project(project_creation, org_id)
```

### Get a project

To get a single project, call `get_project` with the organization and project IDs.

```python
project = unity_cloud.identity.get_project(org_id, project_id)
```

### List users in an organization

To list all users associated to an organization, call `get_organization_user_info_list` with the organization ID.

```python
users = unity_cloud.identity.get_organization_user_info_list(org_id)
```

### List users in a project

To list all users associated to a project, call `get_project_user_info_list` with the organization and project IDs.

```python
users = unity_cloud.identity.get_project_user_info_list(org_id, project_id)
```

### Get a single user

To get the info for a user, call `get_user_info` with the organization and user IDs.

```python
user = unity_cloud.identity.get_user_info(org_id, user_id)
```
