# Variables and OAuth 2

Source: https://apigenie.pl/docs/reference/cli/test/variables
Part of the reference of [test](https://apigenie.pl/docs/reference/cli/test.md).
Its other pages: [Request files](https://apigenie.pl/docs/reference/cli/test/requests.md), [Assertions and scripts](https://apigenie.pl/docs/reference/cli/test/assertions.md), [Validation](https://apigenie.pl/docs/reference/cli/test/validation.md), [Generated requests](https://apigenie.pl/docs/reference/cli/test/generate.md), [GraphQL requests](https://apigenie.pl/docs/reference/cli/test/graphql.md), [WebSocket and MQTT requests](https://apigenie.pl/docs/reference/cli/test/websocket-mqtt.md), [Kafka requests](https://apigenie.pl/docs/reference/cli/test/kafka.md), [AMQP requests](https://apigenie.pl/docs/reference/cli/test/amqp.md), [gRPC requests](https://apigenie.pl/docs/reference/cli/test/grpc.md), [Importing collections](https://apigenie.pl/docs/reference/cli/test/import.md), [httpYac compatibility](https://apigenie.pl/docs/reference/cli/test/httpyac.md).

Where the values of `{{name}}` come from, and how a request gets a token from an OAuth 2 token
endpoint.

## Environments and variables

`{{name}}` is replaced by the variable `name`. Variables come from, the later winning:

1. the environment files of the request file's directory or, when it has none, the working
   directory: `http-client.env.json` (its `$shared` object, then the object of `--env`),
   `http-client.private.env.json` (the same), `.env` and `.env.NAME`;
2. `--env-file` files (JSON like `http-client.env.json`, or `KEY=VALUE` lines);
3. `@name = value` lines outside of requests;
4. what scripts set (`exports`, `client.global.set`);
5. `@name = value` lines of the request's region;
6. `--var NAME=VALUE`.

Responses of named requests can be used in the requests after them:

| Reference | Value |
| --- | --- |
| `{{list.response.status}}` | The status |
| `{{list.response.headers.Location}}` | A header |
| `{{list.response.body.$[0].id}}`, `{{list.response.body./0/id}}` | A value of the JSON body (a path or a JSON pointer) |
| `{{list.response.body}}` | The body |
| `{{list.id}}` | httpYac's form: a value of the JSON body |

Built-in variables: `{{$uuid}}` (and `$guid`, `$random.uuid`), `{{$timestamp}}`, `{{$isoTimestamp}}`,
`{{$datetime iso8601}}`, `{{$datetime rfc1123}}`, `{{$randomInt MIN MAX}}`, `{{$processEnv NAME}}`
and `{{$dotenv NAME}}`. A variable that isn't defined is a warning and stays as it is. `\{{` is a
literal `{{`.

`Authorization: Basic user:password` (or `Basic user password`) is sent base64-encoded, as httpYac
and the JetBrains client do.

## OAuth 2

`Authorization: oauth2 [GRANT] [PREFIX]` gets a token from the token endpoint and sends
`Authorization: Bearer TOKEN` instead, with httpYac's syntax and variables:

```http
GET {{host}}/pets
Authorization: oauth2 client_credentials
```

| Grant | Sent to the token endpoint |
| --- | --- |
| `client_credentials` (when no grant is written) | The client's credentials |
| `password` | `PREFIX_username` and `PREFIX_password` too |
| `refresh_token` | `PREFIX_refreshToken` |

The token request is configured by variables named after the prefix (`oauth2` when no prefix is
written; `Authorization: oauth2 password keycloak` reads `keycloak_tokenEndpoint` and so on). They
come from environment files, `@` variables and `--var`, like any other variable:

| Variable | Meaning |
| --- | --- |
| `oauth2_tokenEndpoint` | The token endpoint's URL (required) |
| `oauth2_clientId` | The client's id (required) |
| `oauth2_clientSecret` | The client's secret; none for a public client |
| `oauth2_scope` | Space-separated scopes |
| `oauth2_audience`, `oauth2_resource` | Sent as `audience` and `resource` when set |
| `oauth2_username`, `oauth2_password` | The `password` grant's user |
| `oauth2_refreshToken` | The `refresh_token` grant's refresh token |
| `oauth2_useAuthorizationHeader` | `true` (the default): the client's id and secret go in a `Basic` `Authorization` header; `false`: in the form |
| `oauth2_issuer` | `openid` only: the token endpoint is read from `ISSUER/.well-known/openid-configuration` when `oauth2_tokenEndpoint` isn't set |

`Authorization: openid ...` is the same, with the OpenID Connect discovery of `oauth2_issuer`.
The token is requested once per run for each configuration (the endpoint, the client, the scopes,
the user) and requested again, with its refresh token when it has one, shortly before its
`expires_in` runs out. The token endpoint is reached like any request: `https://` is verified as
`--ca-cert` and `--insecure` say. A token endpoint that refuses fails the request, which isn't
sent:

```text
FAIL GET http://localhost:8080/pets
    no OAuth 2 token: the OAuth 2 token endpoint http://localhost:8080/token answered 401 (invalid_client: unknown client)
```

The `authorization_code` (or `code`), `implicit` and `device_code` grants need a browser or a
person, and token exchange isn't supported: those requests are skipped with a warning. Tokens,
refresh tokens, client secrets, passwords and the credentials of `Authorization` headers are shown
as `[redacted]` wherever they would appear: in URLs, errors, assertion messages, script logs,
warnings and the reports.
