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

# Get web identity token

> Mint an audience-bound identity proof using an authenticated service-account
or assumed-role session. The selected account must match the session owner.
Human users must first assume an account role. The caller needs
iam:GetWebIdentityToken on its own service-account or role CRN.

The subject is derived from persisted identity, never request fields:
org:ORGANIZATION_UUID:account:ACCOUNT_UUID:role:ROLE_UUID or
org:ORGANIZATION_UUID:account:ACCOUNT_UUID:service-account:SERVICE_ACCOUNT_UUID.
A direct VM metadata session retains its instance:INSTANCE_UUID subject.
Chained sessions represent the target role. Issuer is https://iam.basaltic.sh;
public discovery and workload JWKS are available on that host.

Any permitted external audience is supported, not only AWS. Policy conditions
basalt:IdentityTokenAudience and basalt:IdentityTokenDurationSeconds restrict
issuance. Tokens last at most five minutes and use separate keys from API tokens.
Responses are not cached or stored for idempotency replay. Revoking the source
session prevents further issuance; already issued proofs remain valid until expiry.


> [!NOTE]
>
> Requires the IAM action **`iam:GetWebIdentityToken`**. See [IAM permissions](https://docs.basaltic.sh/iam/permissions.md) for the full list, what each one covers, and an example policy.


## OpenAPI

````yaml /api-reference/specs/iam.yaml post /v1/get-web-identity-token
openapi: 3.0.3
info:
  title: Basaltic IAM API
  version: 1.0.0
  description: >
    Account identity and access management: service accounts, roles, account
    policies, and account-scoped temporary sessions. Authentication and personal
    sign-in remain in IAM. Organizations, accounts, users, groups, and
    organization policies are managed by the Workspace API.


    Roles and custom policies belong to the selected account. Their global CRNs
    use an empty region and the owning account handle. Shared system policies
    use crn:iam:::policy/<name>. Relationship inputs are classified once as CRN,
    UUID, or name, without syntax fallback.


    AssumeRole resolves the target role's owning account. The caller needs
    source permission and the target role must trust the caller; the resulting
    session uses only the target role's permissions, subject to boundaries and
    session restrictions.
  contact:
    name: Basaltic Support
    email: ping@basaltic.sh
  license:
    name: Proprietary
    url: https://basaltic.sh/terms
servers:
  - url: https://iam.basaltic.sh
    description: Global API endpoint
security:
  - BearerAuth: []
paths:
  /v1/get-web-identity-token:
    post:
      tags:
        - IAM
      summary: Get web identity token
      description: >
        Mint an audience-bound identity proof using an authenticated
        service-account

        or assumed-role session. The selected account must match the session
        owner.

        Human users must first assume an account role. The caller needs

        iam:GetWebIdentityToken on its own service-account or role CRN.


        The subject is derived from persisted identity, never request fields:

        org:ORGANIZATION_UUID:account:ACCOUNT_UUID:role:ROLE_UUID or

        org:ORGANIZATION_UUID:account:ACCOUNT_UUID:service-account:SERVICE_ACCOUNT_UUID.

        A direct VM metadata session retains its instance:INSTANCE_UUID subject.

        Chained sessions represent the target role. Issuer is
        https://iam.basaltic.sh;

        public discovery and workload JWKS are available on that host.


        Any permitted external audience is supported, not only AWS. Policy
        conditions

        basalt:IdentityTokenAudience and basalt:IdentityTokenDurationSeconds
        restrict

        issuance. Tokens last at most five minutes and use separate keys from
        API tokens.

        Responses are not cached or stored for idempotency replay. Revoking the
        source

        session prevents further issuance; already issued proofs remain valid
        until expiry.
      operationId: getWebIdentityToken
      parameters:
        - name: X-Account-Id
          in: header
          required: false
          description: >-
            Owning account UUID, CRN, or handle. Defaults to the authenticated
            workload account.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GetWebIdentityTokenRequest'
      responses:
        '200':
          description: External identity proof issued
          headers:
            Cache-Control:
              schema:
                type: string
                enum:
                  - no-store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetWebIdentityTokenResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  schemas:
    GetWebIdentityTokenRequest:
      type: object
      additionalProperties: false
      required:
        - audience
      properties:
        audience:
          type: string
          minLength: 1
          maxLength: 256
          description: >-
            Audience expected by the external relying party. Whitespace, control
            characters and the reserved Basaltic API audience `basaltic` are
            rejected. Permission conditions can restrict the allowed audience.
          example: sts.amazonaws.com
        duration_seconds:
          type: integer
          minimum: 60
          maximum: 300
          default: 300
          description: >-
            Lifetime of the identity proof. Omit for 300 seconds. The
            authenticated session must remain valid for the requested lifetime.
    GetWebIdentityTokenResponse:
      type: object
      required:
        - token
        - expires_at
      properties:
        token:
          type: string
          description: >-
            Signed ES256 JWT for the requested audience. This proof is a
            credential; do not log it. It cannot authenticate to Basaltic APIs.
        expires_at:
          type: string
          format: date-time
          description: Expiration of the identity proof.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
            - request_id
          properties:
            code:
              type: string
              description: Error code identifying the type of error
              example: INVALID_INPUT
            message:
              type: string
              description: Human-readable error message
              example: Invalid request parameters
            params:
              type: object
              additionalProperties: true
              description: >-
                Optional non-sensitive values for interpolation of localized
                errors, keyed by error code. Never present for server errors.
              example:
                instances: 2
                pools: 0
            request_id:
              type: string
              format: uuid
              description: Request ID for debugging
              example: 550e8400-e29b-41d4-a716-446655440000
  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: INVALID_INPUT
              message: Invalid request parameters
              request_id: 550e8400-e29b-41d4-a716-446655440000
    Unauthorized:
      description: Authentication required or token invalid
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: UNAUTHORIZED
              message: Authentication required
              request_id: 550e8400-e29b-41d4-a716-446655440000
    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: ACCESS_DENIED
              message: You don't have permission to perform this action
              request_id: 550e8400-e29b-41d4-a716-446655440000
    TooManyRequests:
      description: >
        Rate limit exceeded. The budget is a fixed window counted per endpoint
        and

        per caller — the authenticated principal when the request carries

        credentials, the client IP otherwise — so one throttled endpoint never

        spends another's budget, and one tenant never spends another's.


        Wait `Retry-After` seconds, then retry. The `X-RateLimit-*` headers ride
        on

        the successful responses of a rate-limited endpoint too, so a client can

        pace itself instead of discovering the ceiling by hitting it.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: RATE_LIMITED
              message: Too many requests, please try again later
              request_id: 550e8400-e29b-41d4-a716-446655440000
      headers:
        Retry-After:
          description: Seconds to wait before retrying. Never zero.
          required: true
          schema:
            type: integer
            minimum: 1
          example: 42
        X-RateLimit-Limit:
          description: Requests allowed per window on this endpoint.
          required: true
          schema:
            type: integer
            minimum: 1
          example: 5
        X-RateLimit-Remaining:
          description: Requests left in the current window. Always 0 on a 429.
          required: true
          schema:
            type: integer
            minimum: 0
          example: 0
        X-RateLimit-Reset:
          description: >-
            Seconds until the window resets — a duration, not a timestamp, so it
            needs no clock agreement between client and server.
          required: true
          schema:
            type: integer
            minimum: 1
          example: 42
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: INTERNAL_ERROR
              message: An internal error occurred
              request_id: 550e8400-e29b-41d4-a716-446655440000
    ServiceUnavailable:
      description: Service temporarily unavailable
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: SERVICE_UNAVAILABLE
              message: The service is temporarily unavailable. Please try again later.
              request_id: 550e8400-e29b-41d4-a716-446655440000
      headers:
        Retry-After:
          description: Seconds to wait before retrying
          schema:
            type: integer
          example: 300
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        An OAuth 2.0 bearer token, sent as `Authorization: Bearer <token>`.
        This is the recommended way to authenticate.

        Get one by exchanging a service account's access key pair at
        `POST /v1/oauth/token` with `grant_type=client_credentials`. It is the
        standard client-credentials grant, so any OAuth-aware library will
        obtain and refresh it for you.

        ```
        curl -s -u "$KEY_ID:$SECRET" -d grant_type=client_credentials \
          https://iam.basaltic.sh/v1/oauth/token
        ```

        Tokens last an hour by default. The same access key pair is separately
        your AWS SigV4 credential for the S3-compatible object endpoint, which
        speaks nothing else.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.