> ## Documentation Index
> Fetch the complete documentation index at: https://qodex.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth profiles

> Run API scenarios as different roles so Qodex can test authorization behavior. Configure identities for role and authorization checks.

# Auth profiles

Auth profiles let the same API scenario run as different identities.

Use them to test whether admins, regular users, viewers, unauthenticated clients, and invalid tokens get the right access.

## How they work

An environment can carry many named auth profiles. Each profile has its own credentials and login config. At run time, a scenario picks one profile and inherits that profile's token for every step.

A profile has two flavors:

* **API**: posts credentials to a login endpoint and extracts a token from the response.
* **UI**: drives Playwright through the login form and captures storage state (plus sniffs a bearer token from network traffic for the API fallback).

Three concrete examples on a `staging` environment:

| Profile name | type | What it logs in as                                      |
| ------------ | ---- | ------------------------------------------------------- |
| `admin`      | api  | A privileged account that can read and write everything |
| `user`       | api  | A regular account scoped to its own resources           |
| `viewer`     | api  | A read-only account                                     |

A scenario that tests IDOR can run once as one `user`, capture that user's `userId`, then run as a different `user` profile and try to read the first user's resource. The expected result is 403. If the API returns 200, the assertion fails and Qodex opens a critical finding.

## Precedence

For API steps, the runner picks an auth source in this exact order:

1. **Static `authToken`** on the environment, if set directly. Overrides everything.
2. **Cached bearer token** if the cache is still fresh (TTL 30 minutes).
3. **`api_login_config`** on the environment (or the chosen `auth_profile.login_config`). Run the login, extract the token.
4. **Browser fallback via `ui_login_steps`**. Drive Playwright through the login form, sniff the bearer token off the network.

The cache is per environment and per profile. Successful logins are cached for 30 minutes. Saving an environment clears the cache. Cached tokens are redacted in API responses.

For UI steps, the runner uses the cached storage state if fresh, otherwise runs `ui_login_steps`.

## Inspect a cached token

When you need to debug a request by hand, the auth profile card can reveal and copy the cached bearer token for that profile.

Use this only for short-lived inspection, such as confirming which role a request is using in the API Playground or comparing a failing scenario against a manual request. Treat the copied value like any other secret: do not paste it into docs, chats, issue trackers, or source control.

## Mint and test a token

For API auth profiles, use the token action on the profile card after you configure the login request.

Qodex sends the profile's login request, extracts the token with the configured `tokenPath`, and stores the result in the same short-lived cache used by scenario runs. If the login request fails, the profile shows the failure so you can correct the URL, body, headers, credentials, or token path before a scenario depends on it.

This is the fastest way to confirm that a profile is ready for the [API Playground](/docs/api-testing-playground), authorization checks, and scheduled runs.

## Manage environments and auth profiles

Open **Knowledge > Environments** to manage an environment, its variables, and its auth profiles.

To delete an environment, select it, click **Delete**, and confirm **Delete**. This cannot be undone. If you only need a variant, use **Duplicate** first so the hosts, variables, and login configuration are copied into a new environment.

To delete an auth profile, select the environment, open **Auth Profiles**, expand the profile, and click **Delete**. Qodex checks whether any scenarios or endpoint samples still reference it. If it finds references, deletion is blocked and it shows the items that must be updated or detached first. Otherwise, confirm **Delete profile**; the profile and its cached token are removed.

When editing variables in an environment, removing a row takes effect when you save the environment. Check that no scenario, Playground request, or auth profile still needs that variable before saving.

## Handle magic links and cookie-based sessions

Not every identity can sign in through an API token exchange. A UI auth profile can now manage an inbox-driven sign-in flow, including a magic link, and retain the browser session it establishes.

Use this for passwordless login, email verification, or an application that authenticates only with session cookies:

1. Configure the UI login steps for the profile, including the email wait step when the app sends a sign-in link.
2. Give the profile its own project inbox label so another profile cannot consume the same login message.
3. Let Qodex open the matching link and verify that the resulting browser session is signed in.

Qodex reuses a confirmed session when it remains valid. This avoids unnecessary magic-link emails and lets API requests stay authenticated when the application has no bearer token.

Keep the profile's credentials and the captured session private. Qodex does not expose session-cookie values in normal project responses.

## The api\_login\_config shape

The HTTP login configuration tells Qodex how to exchange credentials for a token.

```json theme={null}
{
  "url": "${API_BASE_URL}/auth/login",
  "method": "POST",
  "headers": { "Content-Type": "application/json" },
  "body": {
    "email": "${AUTH_EMAIL}",
    "password": "${AUTH_PASSWORD}"
  },
  "tokenPath": "data.access_token"
}
```

What each field does:

* `url`: where to POST. Must resolve to an absolute URL after `${var}` substitution. Bare paths are rejected.
* `method`: usually `POST`. The runner accepts any HTTP verb.
* `headers`: any headers the login endpoint needs. Default `Content-Type: application/json`.
* `body`: the request body. Plain JSON for most APIs, form-encoded for legacy.
* `tokenPath`: dot-notation JSONPath into the response body. `data.access_token` reads `response.data.access_token`. The runner uses a small JSONPath subset, dots only. For exotic paths, write a postscript instead.

The token returned here becomes the cached bearer for every API step in scenarios that pick this profile.

## When this matters

The whole point of running tests as multiple identities is authorization correctness:

* **IDOR** (insecure direct object reference): a `user` profile should not be able to read another user's resources. Run the same scenario as two different `user` profiles, capture an ID from one, request it as the other, assert 403.
* **BOLA** (broken object-level authorization): same idea at the object level. List your orders as one user, then try to load one of those order IDs as another user.
* **Role escalation**: a `viewer` should not be able to write. Run the write scenarios as `viewer` and assert 403 across the board.
* **Endpoint-level auth gating**: an unauthenticated client should get 401 on protected routes. Use a profile with no token (or a deliberately invalid one) to assert that.

You cannot test these correctly with a single shared admin token. The token has to be missing, invalid, lower-privilege, or wrong for the resource on purpose.

## Sample environment with two profiles

```json theme={null}
{
  "name": "staging",
  "hosts": {
    "api": "https://staging.example.com",
    "ui": "https://app-staging.example.com"
  },
  "auth_profiles": [
    {
      "name": "admin",
      "type": "api",
      "credentials": {
        "AUTH_EMAIL": "admin@example.com",
        "AUTH_PASSWORD": "${ADMIN_PASSWORD}"
      },
      "login_config": {
        "url": "${API_BASE_URL}/auth/login",
        "method": "POST",
        "body": { "email": "${AUTH_EMAIL}", "password": "${AUTH_PASSWORD}" },
        "tokenPath": "access_token"
      }
    },
    {
      "name": "user",
      "type": "api",
      "credentials": {
        "AUTH_EMAIL": "user@example.com",
        "AUTH_PASSWORD": "${USER_PASSWORD}"
      },
      "login_config": {
        "url": "${API_BASE_URL}/auth/login",
        "method": "POST",
        "body": { "email": "${AUTH_EMAIL}", "password": "${AUTH_PASSWORD}" },
        "tokenPath": "access_token"
      }
    }
  ]
}
```

Same login endpoint, different credentials, different tokens.

## On the roadmap

<Tip>
  Broader OAuth2 support and clearer reconnect controls for expired credentials are planned.
</Tip>

## Related

<CardGroup cols={2}>
  <Card title="Scenarios" icon="list-checks" href="/docs/api-testing-scenarios">
    See where step.auth attaches.
  </Card>

  <Card title="Chaining and postscripts" icon="link" href="/docs/api-testing-chaining">
    Capture tokens from a login response.
  </Card>

  <Card title="API Playground" icon="terminal" href="/docs/api-testing-playground">
    Run requests with any auth profile.
  </Card>

  <Card title="Auto-verification on save" icon="circle-check" href="/docs/api-testing-auto-verification">
    What gets checked the moment you save.
  </Card>
</CardGroup>
