API
Connecting with AWS Identity Federation
Authenticate to the Twisp GraphQL API using AWS IAM Outbound Identity Federation.
AWS IAM Outbound Identity Federation lets your application obtain a signed JWT from AWS STS using its existing AWS credentials. Twisp accepts this token directly in API requests and uses client policies to authorize access to your ledger.
This guide walks through requesting a token, creating a Twisp client for the AWS issuer, and making a GraphQL request. See Security and Auth for the authentication model and policy reference.
Prerequisites
- An AWS account with outbound identity federation enabled and an IAM role or user allowed to call
sts:GetWebIdentityToken. Follow the AWS setup guide to enable federation and configure permissions. - An AWS CLI version that supports
aws sts get-web-identity-token, configured with credentials for the identity you want to use. These may come from IAM Identity Center or your workload's IAM role. curl,jq, and Python 3 for the command-line examples.- Your Twisp GraphQL endpoint and Twisp account ID, plus existing administrator access to create a client in that tenant.
1. Request an AWS web identity token
Run this command with your application's AWS identity:
AWS_TOKEN_RESPONSE=$(aws sts get-web-identity-token \
--audience ledger-service \
--signing-algorithm RS256 \
--output json)
TWISP_TOKEN=$(printf '%s' "$AWS_TOKEN_RESPONSE" | jq -er '.WebIdentityToken')
The response contains WebIdentityToken, the JWT to send to Twisp, and Expiration, its expiry time. The audience ledger-service identifies the intended recipient; use the same value in the Twisp policy below. See the AWS CLI command reference for the available options.
2. Inspect the token claims
Decode the payload locally to find the issuer and subject that your Twisp client will trust:
printf '%s' "$TWISP_TOKEN" | python3 -c '
import base64, json, sys
payload = sys.stdin.read().strip().split(".")[1]
claims = json.loads(base64.urlsafe_b64decode(payload + "=" * (-len(payload) % 4)))
print(json.dumps(claims, indent=2))
'
This only decodes the claims; it does not verify the signature. An abbreviated payload might look like this:
{
"iss": "https://EXAMPLE.tokens.sts.global.api.aws",
"aud": "ledger-service",
"sub": "arn:aws:iam::123456789012:role/ledger-service",
"iat": 1788796800,
"exp": 1788797100
}
Use your token's actual values in the next step:
issis the AWS account's issuer URL and becomes the Twisp clientprincipal.audidentifies the intended service and is checked by a policy assertion.subidentifies the AWS caller and is checked to restrict access to your chosen role or user.
3. Create a Twisp client and policy
Using your existing Twisp administrator credentials, run the following mutation in the target tenant. Replace the example issuer URL and role ARN with the iss and sub values from your token. The new AWS token can access the ledger only after this client is configured.
mutation CreateAWSFederationClient {
auth {
createClient(
input: {
name: "AWS ledger service"
principal: "https://EXAMPLE.tokens.sts.global.api.aws"
policies: [
{
actions: [SELECT]
resources: ["*"]
effect: ALLOW
assertions: {
isLedgerService: "context.auth.claims.aud == 'ledger-service'"
isAllowedRole: "context.auth.claims.sub == 'arn:aws:iam::123456789012:role/ledger-service'"
}
}
]
}
) {
principal
}
}
}
This policy grants read access across the tenant's resources only when both assertions pass. The subject check limits access to the specified AWS identity; checking the audience alone would also admit other identities under the same issuer that can request that audience.
The example requests one audience and checks its string value. If you request multiple audiences, inspect the resulting aud claim and adapt the assertion to its representation.
Adjust actions and resources for your application's access requirements. See Creating Clients and Policies for resource identifiers and policy evaluation, and CEL for assertion syntax.
4. Call the Twisp GraphQL API
Set your endpoint and Twisp account ID. The Twisp account ID selects your tenant; it is separate from the AWS account number in the role ARN.
TWISP_ENDPOINT='https://api.us-east-1.cloud.twisp.com/financial/v1/graphql'
TWISP_ACCOUNT_ID='<your-twisp-account-id>'
Use the endpoint for your environment. If the token expired while you configured the client, repeat step 1, then query accounts:
curl --fail-with-body --silent --show-error "$TWISP_ENDPOINT" \
-H "Authorization: Bearer $TWISP_TOKEN" \
-H "x-twisp-account-id: $TWISP_ACCOUNT_ID" \
-H 'Content-Type: application/json' \
--data-raw '{"query":"query { accounts(index: { name: STATUS }, first: 5) { nodes { accountId code name } } }"}'
Twisp validates the token, looks up the client by its issuer, and evaluates the client's policies against the request. A successful response contains data.accounts.nodes, which can be empty if the tenant has no accounts. Check the response body for GraphQL errors as well as the HTTP status; see Response Format.
5. Refresh tokens in your application
AWS tokens default to a five-minute lifetime. Cache the token in memory and request a replacement before the returned Expiration time, allowing time for requests in flight. Use the AWS SDK's GetWebIdentityToken operation in your application to repeat the same flow. The AWS CLI reference describes token duration options.
Reuse a valid token across requests and coordinate refreshes within your application to avoid unnecessary STS calls. Keep tokens out of logs and ensure the AWS credentials used to refresh them remain valid.
Troubleshooting
- AWS rejects the token request: Confirm that outbound federation is enabled and the calling identity has
sts:GetWebIdentityTokenpermission. Check that its AWS credentials are still valid. - The CLI does not recognize the command: Update to an AWS CLI version that supports
get-web-identity-token. - Twisp rejects authentication: Request a fresh token and check that you sent the complete JWT and the correct
x-twisp-account-idheader. - Twisp denies access: Check that a client exists in the selected tenant with
principalexactly matchingiss, both assertions match the token, and the policies allow the requested resources and actions. A matchingDENYpolicy takes precedence.
For this flow, the client principal is the AWS issuer URL. The Twisp-issued IAM token flow exchanges a presigned GetCallerIdentity request and uses an AWS identity ARN as the principal; it is a separate authentication option.