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

# How to secure connections

> Authenticate as an organization member, initialize signing keys, create a Builder, and generate a Builder JWT to call the Frontend API.

## Before you begin

**Roles & credentials**

* Organization member credentials for the **Sutro API** (email and password).

**Tools**

* `curl`, `jq`, `uuidgen`, and the `jwt` CLI.
* Node.js (optional) if you prefer the JavaScript example.
* UNIX shell (macOS/Linux) or WSL on Windows.

**Variables you'll need**

* `<ORG_MEMBER_EMAIL>` — Email for an organization member.
* `<ORG_MEMBER_PASSWORD>` — Password for that account.
* `<COMMON_NAME>` — Friendly name for the certificate to generate (e.g., "Staging key").
* `<JWT_ISSUER>` — Issuer string to embed in Builder JWTs (e.g., your org slug or auth issuer).

<Info>All placeholders appear in **angle brackets** and must be replaced before running commands.</Info>

## Steps

Sutro walks you through each credential step so you stay in charge of the entire security chain—from login to Builder-issued tokens—with Sutro validating every move.

<Steps>
  <Step title="Authenticate as an organization member">
    Use your organization member credentials to obtain an access token.

    <CodeGroup dropdown>
      ```sh theme={null}
      curl -H "Content-Type: application/json" \
           -X POST \
           -d '{"email":"<ORG_MEMBER_EMAIL>","password":"<ORG_MEMBER_PASSWORD>"}' \
           -o auth.json \
           https://sapi.withsutro.com/login

      # Store the access token for subsequent requests
      ORG_MEMBER_JWT=$(jq -r '.access_token' < auth.json)
      ```

      ```javascript theme={null}
      const user = process.env.ORG_MEMBER_EMAIL
      const password = process.env.ORG_MEMBER_PASSWORD;

      const { access_token: memberJwt } = await fetch(
        "https://sapi.withsutro.com/login",
        {
          method: "POST",
          body: JSON.stringify({ user, password }),
          headers: { "Content-Type": "application/json" },
        }
      ).then((x) => x.json());

      ```
    </CodeGroup>

    <Card title="Replace these placeholders">
      | Placeholder             | Meaning                                           |
      | ----------------------- | ------------------------------------------------- |
      | `<ORG_MEMBER_EMAIL>`    | Email of an organization member with login access |
      | `<ORG_MEMBER_PASSWORD>` | Password for that account                         |
    </Card>
  </Step>

  <Step title="Initialize your organization">
    Provision a certificate and private key for signing Builder JWTs.

    <CodeGroup dropdown>
      ```sh theme={null}
      curl -H "Content-Type: application/json" \
           -H "Authorization: Bearer ${ORG_MEMBER_JWT}" \
           -X POST \
           -d '{"commonName": $COMMON_NAME, "jwtIssuer": $JWT_ISSUER}' \
           -o certs.json \
           https://sapi.withsutro.com/initialization

      # Save the certificate and private key to files and capture the certificate ID and API Client Identifier
      CERTIFICATE_ID=$(jq -r '.certificate.id' < certs.json)
      API_CLIENT_IDENTIFIER=$(jq -r '.apiClientIdentifier' < certs.json)
      jq -r '.privateKey' < certs.json > mtls.key
      jq -r '.certificate.content' < certs.json > mtls.crt
      ```

      ```javascript theme={null}
      const { certificate: {id: certificateId, content: certificate}, privateKey, apiClientIdentifier } = await fetch(
           "https://sapi.withsutro.com/initialization",
           {
                method: "POST",
                body: JSON.stringify({"commonName": process.env.COMMON_NAME, "jwtIssuer": process.env.JWT_ISSUER}),
                headers: { 
                     "Authorization": `Bearer ${memberJwt}`,
                     "Content-Type": "application/json" 
                },
           }
      ).then((x) => x.json());
      ```
    </CodeGroup>

    <Card title="Replace these placeholders">
      | Placeholder     | Meaning                                                          |
      | --------------- | ---------------------------------------------------------------- |
      | `<COMMON_NAME>` | Friendly label for the certificate (e.g., "Production key")      |
      | `<JWT_ISSUER>`  | The value you expect to place in the `iss` claim of Builder JWTs |
    </Card>

    > The file `mtls.key` contains your **private key**. Store it securely and restrict file permissions.
  </Step>

  <Step title="Create a Builder">
    Create a Builder and record its `sid`. You'll use this value as the JWT subject (`sub`).

    <CodeGroup dropdown>
      ```sh theme={null}
      BUILDER_SID=$(uuidgen)
      curl -H "Content-Type: application/json" \
           -H "Authorization: Bearer ${ORG_MEMBER_JWT}" \
           -X POST \
           -d "{\"sid\": \"$BUILDER_SID\"}" \
           -o builder.json \
           https://sapi.withsutro.com/builders
      ```

      ```javascript theme={null}
      const builderSid = crypto.randomUUID();
      const { id: builderId } = await fetch(
           "https://sapi.withsutro.com/builders",
           {
                method: "POST",
                body: JSON.stringify({"sid": builderSid}),
                headers: { 
                     "Authorization": `Bearer ${memberJwt}`,
                     "Content-Type": "application/json" 
                },
           }
      ).then((x) => x.json());
      ```
    </CodeGroup>

    > **Important:** The JWT `sub` **must equal** the Builder's `sid`.
  </Step>

  <Step title="Generate a Builder JWT with the CLI">
    Use the `jwt` CLI to sign a short-lived access token with your private key.

    <CodeGroup dropdown>
      ```sh theme={null}
      # Generate a signed Builder JWT (1 hour expiration)
      BUILDER_JWT=$(jwt encode --secret @mtls.key \
                 -A RS256 \
                 --iss "$JWT_ISSUER" \
                 --sub "$BUILDER_SID" \
                 --aud "https://sapi.withsutro.com" \
                 --jti $(uuidgen) \
                 --exp=$(($(date +%s) + 3600)))

      echo "${BUILDER_JWT}"
      ```
    </CodeGroup>

    <Card title="Replace or verify these values">
      | Field | Meaning                                                  |
      | ----- | -------------------------------------------------------- |
      | `iss` | Must match `<JWT_ISSUER>` you set during initialization  |
      | `sub` | Must equal the Builder's `sid` (`${BUILDER_SID}`)        |
      | `aud` | Audience of the Sutro API: `https://sapi.withsutro.com`  |
      | `exp` | Expiration time (Unix seconds). The example uses 1 hour. |
    </Card>
  </Step>

  <Step title="Generate a Builder JWT in JavaScript (optional)">
    If you prefer Node.js:

    ```javascript theme={null}
    import crypto from "node:crypto";
    import jwt from "jsonwebtoken";
    import fs from "node:fs";

    const privateKey = fs.readFileSync("mtls.key", "utf8");
    const builderSid = process.env.BUILDER_SID; // set from the previous step
    const issuer = process.env.JWT_ISSUER;      // set to <JWT_ISSUER>

    const accessToken = jwt.sign(
      {},
      privateKey,
      {
        algorithm: "RS256",
        expiresIn: "1h",
        jwtid: crypto.randomUUID(),
        audience: "https://sapi.withsutro.com",
        subject: builderSid,
        issuer,
      }
    );

    console.log(accessToken);
    ```

    > Set `BUILDER_SID` and `JWT_ISSUER` in your environment before running the script.
  </Step>

  <Step title="Verify your JWT (optional)">
    * Inspect claims and signature at [https://jwt.io/](https://jwt.io/).
    * Your public certificate is in `mtls.crt` (PEM).

    ```sh theme={null}
    # View the PEM-encoded public certificate
    cat mtls.crt
    ```
  </Step>
</Steps>

<Check>Your organization keys and Builder JWT flow are locked down—keep building knowing every API call is authenticated and auditable.</Check>

## Reference

* **POST `/login`** — Exchange organization member credentials for a JWT used to administer your organization.
* **POST `/initialization`** — Provision a certificate and private key used to sign Builder JWTs.
* **POST `/builders`** — Create a Builder and obtain its `sid`.
* **Builder JWT claims** — `iss` (issuer), `sub` (Builder `sid`), `aud` (`https://sapi.withsutro.com`), `jti`, `exp`.

## Next steps

* [Build a full-stack app](/docs/getting-started/building-full-stack-apps) using your Builder JWT
* Review the [API Reference](/api-reference/projects/get-a-list-of-projects) for all available endpoints
