Skip to main content

Authentication

Overview​

The Lyriq Connector accepts only access tokens issued by the platform IAM (Lyriq IAM).

Any other tokens are explicitly unsupported and will be rejected:

  • raw FIS IdP tokens;
  • raw bank IdP tokens;
  • raw SAML assertions;
  • upstream IdP claim payloads.

Which token flow should I use?​

CallerSupported flow
FIS IdP human userIAM authorization-code flow with the FIS IdP broker (see Human users)
Bank SSO human userIAM authorization-code flow with the bank IdP broker (see Human users)
Bank backend or system clientFIS workload assertion exchanged at IAM with client_credentials and JWT client authentication (see Bank backends)
Raw FIS token, raw bank token, or SAML assertionUnsupported

The IAM endpoints below are served by the platform IAM host, not by the Lyriq Connector.

Sending the token​

Every endpoint requires the token as a bearer credential. Requests sent without it are rejected immediately with 401 Unauthorized.

export CONNECTOR_URL=<your-connector-base-url>
export TOKEN=<paste_your_token_here>
curl "$CONNECTOR_URL/v1/operations" \
--header "Authorization: Bearer $TOKEN" \
--header "Accept: application/vnd.api+json"

Mutating requests additionally send Content-Type: application/vnd.api+json and an Idempotency-Key header.

What's in the access token​

The access token is a signed JWT. You never build or edit it: the platform IAM mints it from the configuration approved when your bank was onboarded, and the Lyriq Connector validates every claim below on every request. A token issued to a bank backend (M2M workload) through the client_credentials flow looks like this once decoded:

{
"iss": "https://iam.example.com/realms/keystone-network",
"sub": "6f1c2d3e-4b5a-4c6d-8e7f-9a0b1c2d3e4f",
"aud": ["bank-connector"],
"azp": "bank-m2m-01927c3e-8b4a-7d21-9f3e-5a6b7c8d9e0f",
"iat": 1790000000,
"exp": 1790000300,
"scope": "connector:transfers:create connector:operations:read",
"connector_token_version": "v1",
"principal_type": "service_account",
"principal_kind": "bank_member",
"connector_managed_client": true,
"bank_memberships": [
{
"bank_id": "11111111-1111-7111-8111-111111111111",
"roles": ["maker"],
"scopes": ["connector:transfers:create", "connector:operations:read"]
}
]
}
ClaimWhat it holdsWhat the Lyriq Connector checks
issThe platform IAM issuer URL for your deploymentMust be a trusted platform issuer; a token from any other issuer is rejected
subThe platform's identifier for your workloadMust be a UUID; recorded as the acting principal in audit
audThe intended recipients of the tokenMust include bank-connector
azpThe platform client id generated for your workload at onboarding (shown as Platform client ID in the bank portal)Must be a client the platform recognises for the Lyriq Connector
iat, expIssue and expiry times, in seconds since the epochexp must be in the future; tokens live 300 seconds
scopeSpace-separated API capabilities granted to the workloadSee How scopes are resolved
connector_token_versionThe version of this claim contractMust be v1
principal_typeThe kind of caller: service_account for an M2M workload, a user type for a person signed in through a browser flowMust be present
principal_kindbank_member for every bank callerMust be bank_member on bank-facing routes
connector_managed_clienttrue when the workload was provisioned through bank onboardingTogether with principal_type and principal_kind, marks the client as one the platform created for your bank
bank_membershipsThe banks this caller may act for, each with its bank_id, descriptive roles and approved scopesSee Selecting the target bank

Every value comes from onboarding: the bank, the roles and the scopes are those approved for the workload, so the token for an M2M workload always carries exactly one membership. To change what a workload may do, change its onboarding configuration; requesting a different token does not widen it.

To inspect a token, decode its middle segment:

jq -R 'split(".")[1] | gsub("-"; "+") | gsub("_"; "/") | @base64d | fromjson' <<< "$TOKEN"

How scopes are resolved​

A request is allowed a scope only when it appears in both the token's top-level scope and the scopes of the selected bank membership. A scope present in only one of the two is not granted. Each endpoint in this specification names the scope it requires.

Scopes describe coarse API capabilities, such as connector:transfers:create. They never name a bank, an account or an asset; which bank a request acts for comes only from bank_memberships. The roles in a membership (for example maker, checker or readonly) are descriptive labels for the preset the workload was created from. They grant nothing on their own.

Selecting the target bank​

The token's bank_memberships claim lists the banks the caller may act on, for example:

"bank_memberships": [
{
"bank_id": "11111111-1111-7111-8111-111111111111",
"roles": ["maker"],
"scopes": ["connector:transfers:create", "connector:operations:read"]
},
{
"bank_id": "22222222-2222-7222-8222-222222222222",
"roles": ["readonly"],
"scopes": ["connector:operations:read"]
}
]

With exactly one membership the Lyriq Connector selects it automatically. With more than one, declare the target explicitly with the bank's UUID:

--header "x-dan-bank-id: 11111111-1111-7111-8111-111111111111"

Send the header at most once. A value that is empty, not a UUID, or not one of your memberships is rejected with 403 Forbidden and code BANK_SCOPE_MISMATCH.

Human users: authorization-code flow​

FIS IdP users and bank SSO users start authentication at the platform IAM realm. The IAM redirects the user to the configured upstream identity provider, accepts the successful upstream authentication response, applies the configured mappers, and issues the normalized Lyriq Connector access token.

User
-> platform IAM authorization endpoint
-> FIS IdP (or bank SSO) login
-> platform IAM mapper configuration
-> IAM-issued Lyriq Connector access token
-> Lyriq Connector API

The token sent to the Lyriq Connector is always the IAM-issued access_token. Do not send the raw FIS IdP token, raw SAML assertion, or copied upstream FIS claims to the Lyriq Connector.

Start the brokered login​

Start an OIDC authorization-code flow against the IAM. Public browser clients should use PKCE. The kc_idp_hint parameter is optional; when it is set to the configured identity-provider alias (for example the FIS IdP alias), the IAM routes the user directly to that provider's login instead of showing the identity-provider selector.

export IAM_AUTH_URL="https://<iam-host>/realms/keystone-network/protocol/openid-connect/auth"
export CLIENT_ID="bank-portal"
export REDIRECT_URI="https://<portal-host>/oauth/callback"
export FIS_IDP_ALIAS="fis"

# Open this URL in the user's browser. URL-encode redirect_uri before sending it.
"$IAM_AUTH_URL?client_id=$CLIENT_ID&response_type=code&redirect_uri=<url-encoded-redirect-uri>&scope=openid%20profile%20email&state=<opaque-state>&code_challenge=<pkce-code-challenge>&code_challenge_method=S256&kc_idp_hint=$FIS_IDP_ALIAS"

After the user authenticates, the IAM redirects back to the registered redirect_uri with an authorization code.

Exchange the code at the IAM​

Exchange the authorization code at the IAM token endpoint. Use the same redirect URI and PKCE verifier that were used to start the login.

export IAM_TOKEN_URL="https://<iam-host>/realms/keystone-network/protocol/openid-connect/token"
export CLIENT_ID="bank-portal"
export REDIRECT_URI="https://<portal-host>/oauth/callback"
export AUTHORIZATION_CODE="<code-from-iam-redirect>"
export CODE_VERIFIER="<original-pkce-code-verifier>"

curl -sS -X POST "$IAM_TOKEN_URL" \
-H 'content-type: application/x-www-form-urlencoded' \
-d grant_type=authorization_code \
-d "client_id=$CLIENT_ID" \
-d "redirect_uri=$REDIRECT_URI" \
-d "code=$AUTHORIZATION_CODE" \
-d "code_verifier=$CODE_VERIFIER"

For confidential interactive web applications, include the registered client secret in the token request. This applies only to the web application's OIDC registration, never to a bank M2M workload:

-d "client_secret=$CLIENT_SECRET"

Use the access_token from the response as the bearer token for the Lyriq Connector.

Bank backends: workload assertion exchange​

Bank backend and system integrations authenticate to FIS with a bank-controlled asymmetric credential. FIS returns a short-lived workload assertion whose sub is the FIS Client ID registered during bank onboarding. The platform IAM verifies that assertion and resolves it to the secretless federated client provisioned for the workload. This flow is for machine-to-machine clients only; human users use the authorization-code flow above.

Obtain the FIS workload assertion from the FIS token endpoint using the bank-controlled credential, then exchange it once at the IAM:

export IAM_TOKEN_URL="https://<iam-host>/realms/keystone-network/protocol/openid-connect/token"
export FIS_WORKLOAD_ASSERTION="<short-lived-assertion-from-fis>"

curl --fail --show-error --silent --request POST "$IAM_TOKEN_URL" \
-H 'content-type: application/x-www-form-urlencoded' \
-d grant_type=client_credentials \
-d 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode "client_assertion=$FIS_WORKLOAD_ASSERTION"

The access token is valid for 300 seconds; request a new one before it expires. Its claims, including the bank membership and scopes approved for the workload at onboarding, are described in What's in the access token.

Common problems​

Missing bearer token​

Ensure the Authorization header is present exactly once and uses the Bearer <token> syntax. The response is 401 with code AUTHENTICATION_REQUIRED.

Expired token​

Access tokens expire after 5 minutes (300 seconds). Requests using an expired token are rejected with 401 (title Expired token); get a new one via the relevant flow.

Wrong issuer or audience​

Occurs when passing a token issued directly by an external entity instead of the platform IAM, or when the requesting client isn't configured with the Lyriq Connector audience. The response is 401 with code AUTHENTICATION_REQUIRED.

Request a new token from the IAM using the relevant flow. If the problem persists, contact your system administrator to verify the client's audience configuration.

Missing scope​

The token is valid but lacks the permission scope the endpoint requires; the response is 403 with code UNAUTHORIZED_SCOPE. Check the endpoint's required scope in this specification against both the token's scope and the selected membership's scopes (see How scopes are resolved). A fresh token carries the same scopes, so if the scope is missing from either, contact your system administrator to update your client's access rights.

Missing or ambiguous bank membership​

Missing: the token's bank_memberships array is empty, so the caller has no bank relationship yet (403, title Missing bank membership). Contact your system administrator to provision one.

Ambiguous: the array has more than one entry and the request didn't declare a target bank (403, title Bank selector required). Resolve it with the x-dan-bank-id header described in Selecting the target bank.

Suspended or terminated bank​

Requests for a bank that is suspended or terminated on the network are rejected with 403 and code BANK_SUSPENDED or BANK_TERMINATED.