Skip to content

Writing authentication procedures

In case you did not find a preset suited for your need, you can write your own procedures manually.

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.

Most of the time, a procedure will be a sequence of one or more HTTP requests, but it can also include other types of operations, like a Selenium script mocking a browser navigation, or a request against a GraphQL server.

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. Depending on the type of operation, the configuration structure might vary.

It consists of an array of operations. An operation is a single action to execute, like a request, a Selenium script, or a GraphQL query. 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.

Combining operations

Operations of different types can be combined within a procedure! As an example, authenticating against an OIDC server, using an authorization code flow might require you to:

  1. Declare a Selenium 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.

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

Consider Using the cURL Sequence Preset

This example demonstrates how to manually build a token-based authentication flow using HTTP requests. However, this pattern can be implemented more simply using Escape's built-in cURL Sequence Preset, which provides a streamlined configuration for sequential HTTP requests. This example is provided for educational purposes to illustrate how procedures, operations, extractions, and injections work together.

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), you can configure any HTTP parameter: url, method, headers, cookies, body, queryParameters, username, password, and even a proxy. Only url and method are required.
  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. The location can be body, header, or cookie, and the 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 (e.g., 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

Consider Using the OAuth2 Auth Code Flow Preset

This example demonstrates how to manually implement an OAuth 2.0 Authorization Code flow using browser actions. However, this can be done directly using Escape's built-in OAuth2 Auth Code flow preset, which is simpler and more maintainable. This example is provided for documentation purposes to illustrate advanced workflow combinations.

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 allows automated browser navigation to handle interactive OAuth login flows that cannot be performed via pure HTTP requests.
  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.