# Writing Authentication Procedures

Write custom authentication procedures to define the steps your application needs and combine browser actions with HTTP requests.

A procedure is a sequence of operations to execute against an application, that aims at **generating variables** to be reused later on to build a user's authentication credentials.

A procedure can include HTTP requests, browser actions, or a combination of both.

A procedure is defined as a JSON object, with the following properties:

- `name`: the name of the procedure, used to reference it later on within the configuration file. It must be unique across procedures.
- `operations`: an array of operations to execute, in order. Each operation *must* include a `tech` property, indicating the type of operation to execute. The operation's `tech` value determines its configuration structure.

The customer-facing `tech` values are `http`, `oauth_authz_code_browser`, `browser_agent`, and `browser_actions`. See the [Authentication Reference](<https://docs.escape.tech/documentation/reference/authentication-reference/index.md>) for each operation's parameters.

It consists of an array of `operations`. An operation is a single action to execute, like an HTTP request or a browser actions sequence. It also declares how to extract variables from the response of the operation, if any. These variables can then be reused later on to declare users.

> [!NOTE]
>
> **Combining Operations**
>
> Combine operations of different types within a procedure. For example, an OIDC authorization code flow can use these steps:
>
> 1. Declare a browser actions operation to navigate to the authentication portal of the OIDC server and retrieve an authorization code
> 2. Use an HTTP request to trade the retrieved token for an access token and a refresh token.

## Understanding Injections and Extractions

Extractions are crucial for deriving variables from the responses of operations. These variables are then available for use in subsequent steps of the procedure. The extraction process involves specifying the location (such as the body or header of a response) and the key for the data to be extracted, and the potential regex to extract specific data within the key.

Injections are used to incorporate extracted variables into the final credentials generated for the user. This process involves specifying the location (such as a header or cookie), the key where the variable should be inserted, and the potential prefix of the token.

HTTP extractions and injections support `body`, `header`, `cookie`, and `query`. Browser locations are `browser_cookies`, `browser_local_storage`, `browser_session_storage`, and `page`. A `page` extraction uses a Playwright selector; browser storage and cookie extractions also specify an `origin`.

> [!NOTE]
>
> **Multiple Variables**
>
> Note that if necessary, multiple variables can be injected at the end of the procedure.

## Templating in Procedures

Escape's authentication procedures support Jinja templating, allowing the injection of extracted variables into subsequent operations. This templating feature includes all standard Jinja functions, plus the ability to `base64` encode values.

## Example 1: Token-Based Authentication with HTTP Requests

> [!TIP]
>
> **Use the cURL Sequence Preset for Sequential HTTP Requests**
>
> Use the [cURL Sequence preset](<https://docs.escape.tech/documentation/platform/authentication/curlsequence/index.md>) to configure sequential HTTP requests. The custom procedure below shows how operations, extractions, and injections work together.

```yaml
procedures:
  # (1)
  - name: token-auth-procedure  # (2)
    operations:
      # (3)
      - tech: http
        parameters:
          url: "https://api.example.com/auth/login"  # (4)
          method: POST
          headers:
            - name: Content-Type
              values:
                - application/json
          body: '{"username": "{{ username }}", "password": "{{ password }}"}'  # (5)
        extractions:
          # (6)
          - name: session_token
            location: body
            key: token
          - name: user_id
            location: body
            key: userId
      # (7)
      - tech: http
        parameters:
          url: "https://api.example.com/auth/refresh"
          method: POST
          headers:
            - name: Content-Type
              values:
                - application/json
            - name: X-User-ID
              values:
                - "{{ user_id }}"  # (8)
          body: '{"token": "{{ session_token }}"}'
        extractions:
          - name: access_token
            location: body
            key: accessToken  # (9)
    injections:
      # (10)
      - location: header
        key: Authorization
        prefix: "Bearer "
        variable: access_token
users:
  # (11)
  - name: regular_user
    credentials:
      username: test.user@example.com  # (12)
      password: SecurePassword123!
    procedure: token-auth-procedure  # (13)
  - name: admin_user
    credentials:
      username: admin@example.com
      password: AdminPass456!
    procedure: token-auth-procedure
```

1. This authentication procedure demonstrates a common token-based authentication flow with two sequential HTTP requests.
2. The procedure name `token-auth-procedure` must be unique across all procedures in the configuration file, as it will be referenced when declaring users.
3. The first operation is an HTTP POST request to a login endpoint. Each operation in a procedure is executed in the order it appears.
4. For HTTP requests (with `tech` set to `http`), the parameters are `url`, `method`, `headers`, `cookies`, `body`, `queryParameters`, `timeout`, `insecure`, `follow_redirects`, and `proxy_override`. Only `url` is required; `method` defaults to `POST`. Put user credentials in the user's `credentials` block and reference them through templates.
5. The request body uses Jinja templating to inject user credentials. The `username` and `password` variables will be automatically provided from the user's credentials defined later in the configuration.
6. After each operation, you can define extractions to capture data from the response. Here, we extract both a `session_token` and a `user_id` from the JSON response body. For HTTP operations, `location` can be `body`, `header`, `cookie`, or `query`, and `key` specifies which field to extract.
7. The second operation makes another HTTP request, this time to refresh or upgrade the token. This demonstrates how operations can be chained together in a sequence.
8. Variables extracted in previous operations can be reused in subsequent requests using the Jinja template syntax `{{ variable_name }}`. Here, we inject the `user_id` as a header and the `session_token` in the request body.
9. The final access token is extracted from the second response and stored in the `access_token` variable, which will be used for authentication in all subsequent API requests during the scan.
10. The `injections` section defines how the extracted variables should be injected into authenticated requests. This example adds the access token as an `Authorization` header with a `Bearer` prefix. Multiple injections can be defined if needed (for example, injecting tokens into both headers and cookies).
11. Users are defined separately from procedures, allowing you to create multiple test users with different credentials, all using the same authentication workflow.
12. Each user specifies their credentials, which will be injected into the procedure at runtime. The credential fields must match the template variables used in the procedure (in this case, `username` and `password`).
13. The `procedure` field links each user to their authentication workflow. Multiple users can share the same procedure but with different credentials, which is useful for testing role-based access control (RBAC).

## Example 2: OAuth Authorization Code Flow with Browser Actions

> [!TIP]
>
> **Use the OAuth Authorization Code Preset for Standard Flows**
>
> Use the [OAuth Authorization Code preset](<https://docs.escape.tech/documentation/platform/authentication/oauthauthzcode/index.md>) to configure this flow directly. The custom procedure below shows how to combine browser actions with HTTP requests.

```yaml
procedures:
  # (1)
  - name: browser_oauth  # (2)
    operations:
      - tech: browser_actions  # (3)
        parameters:
          login_url: https://oauth.example.com/authorize?client_id=your-client-id&redirect_uri=https://httpbin.tools.escape.tech/get&scope=oauth
          logged_in_detector_text: code  # (4)
          logged_in_detector_timeout: 10
          stealth_mode: false
        extractions:
          # (5)
          - location: page
            origin: https://httpbin.tools.escape.tech/get
            key: body
            name: authorization_code
            regex: '"code": "([\w\d-]+)"'
      # (6)
      - tech: http
        parameters:
          url: https://api.example.com/oauth/v1/token  # (7)
          method: POST
          headers:
            - name: Content-Type
              values:
                - application/x-www-form-urlencoded
          cookies: []
          queryParameters: []
          body: grant_type=authorization_code&client_id=your-client-id&client_secret=your-client-secret&redirect_uri=https://httpbin.tools.escape.tech/get&code={{authorization_code}}  # (8)
        extractions:
          - location: body
            key: access_token
            name: access_token  # (9)
    injections:
      # (10)
      - location: header
        key: Authorization
        prefix: "Bearer "
        variable: access_token
users:
  # (11)
  - name: user1
    credentials:
      username: user@example.com
      password: SecureP@ssw0rd123
      actions:
        # (12)
        - action: goto
          url: https://oauth.example.com/authorize?client_id=your-client-id&redirect_uri=https://httpbin.tools.escape.tech/get&scope=oauth
        - action: click
          locator: button[data-test-id="login-button"]
        - action: fill
          locator: input[data-test-id="email-input-field"]
          value: user@example.com
        - action: click
          locator: button[data-test-id="password-login-button"]
        - action: fill
          locator: input[data-test-id="password-input-field"]
          value: SecureP@ssw0rd123
        - action: click
          locator: button[data-test-id="password-login-button"]
        - action: goto
          url: https://oauth.example.com/authorize?client_id=your-client-id&redirect_uri=https://httpbin.tools.escape.tech/get&scope=oauth
    procedure: browser_oauth  # (13)
```

1. This procedure combines browser automation with HTTP requests to implement a complete OAuth 2.0 Authorization Code flow.
2. The procedure name `browser_oauth` uniquely identifies this workflow and will be referenced in the user configuration.
3. The `browser_actions` tech automates browser navigation for interactive OAuth login flows.
4. The `logged_in_detector_text` parameter specifies text that should appear on the page to confirm successful authentication. Here, we wait for the word "code" to appear after the OAuth redirect, indicating we've received an authorization code.
5. After the browser operation completes, we extract the authorization code from the redirect URL's response body using a regex pattern. This code is stored in the `authorization_code` variable.
6. The second operation is a standard HTTP request to exchange the authorization code for an access token.
7. The token endpoint URL is specific to your OAuth provider. This is where you'll receive the access token in exchange for the authorization code.
8. The request body includes all required OAuth parameters, with the authorization code being injected via templating: `{{authorization_code}}`. The `grant_type` is set to `authorization_code` per the OAuth 2.0 specification.
9. The access token is extracted from the response body and stored in the `access_token` variable for later injection.
10. The `injections` section defines how the extracted access token should be injected into subsequent authenticated requests. Here, it will be added as an `Authorization` header with the `Bearer` prefix (including a trailing space).
11. Users are defined separately, allowing you to declare multiple test users with different credentials, all using the same procedure.
12. The `actions` array defines the sequence of browser interactions needed to complete the OAuth login flow. These actions include navigation, clicking buttons, and filling form fields. This is where the actual user credentials are used to log in through the OAuth provider's interface.
13. Each user references the procedure they should use, linking the credentials to the authentication workflow.
