Linked App Token
The Linked App Token policy selector allows an Access policy on one application to accept tokens issued for another application. This is useful when one application needs to make authenticated requests to another on behalf of a user — for example, an MCP server calling internal APIs, or a microservice forwarding user identity to a downstream service.
Linked App Token supports two flows:
- Self-hosted to self-hosted — A self-hosted application forwards its Access JWT to another self-hosted application. This is the simplest setup and requires no additional OAuth configuration.
- SaaS to self-hosted — An Access for SaaS application (such as an MCP server using OAuth) sends its OAuth access token to a self-hosted application.
In this flow, Application A is a self-hosted Access application that needs to make requests to Application B, another self-hosted Access application. When a user authenticates to Application A, Cloudflare Access sends the user's JWT to Application A in the Cf-Access-Jwt-Assertion header. Application A can then forward that token to Application B in the Cf-Access-Token header. Access will validate the token against the Linked App Token rule on Application B's policy and allow the request if the token was issued for Application A.
flowchart LR
accTitle: Self-hosted to self-hosted linked app token flow
User --> appA["Application A <br> (self-hosted)"]
appA -- "Cf-Access-Token: <JWT>" --> appB["Application B <br> (self-hosted)"]
idp[Identity provider] <--> appA
Create a policy on Application B (the downstream application that will receive forwarded requests):
-
In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Applications.
-
Select Application B and select Edit.
-
Go to the Policies tab and select Create new policy.
-
Set the policy Action to Service Auth.
-
For Selector, select Linked App Token.
-
For Value, select Application A. For example,
Action Rule type Selector Value Service Auth Include Linked App Token application-a -
Save the policy.
-
In Application B, add the policy to the Access policies list.
-
Save the application.
-
Get the
uidof Application A:
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies RevokeAccess: Apps and Policies WriteAccess: Apps and Policies Read
List Access applications curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps" \--request GET \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"Response {"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","type": "self_hosted","name": "application-a",...} -
Create an Access policy on the downstream application, replacing the
app_uidvalue with theuidof Application A:
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies Write
Create an Access reusable policy curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/policies" \--request POST \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--json '{"name": "Allow requests from Application A","decision": "non_identity","include": [{"linked_app_token": {"app_uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}]}'
When Cloudflare Access authenticates a user to Application A, it sends a signed JWT in the Cf-Access-Jwt-Assertion request header. Application A must forward this token to Application B in the Cf-Access-Token header:
Cf-Access-Token: <JWT from Cf-Access-Jwt-Assertion>When Access receives the request to Application B, it will:
- Extract the token from the
Cf-Access-Tokenheader. - Validate that the token was issued for Application A (matching the
app_uidin the Linked App Token rule). - If valid, allow the request. The user's identity from the token is propagated to the upstream headers and audit log.
In this example an Access for SaaS application (for example, an MCP server that implements OAuth ↗) needs to make requests to a self-hosted Access application. The SaaS app obtains an OAuth access token from Cloudflare Access and sends it to the self-hosted application in the Authorization: Bearer header.
flowchart LR
accTitle: SaaS to self-hosted linked app token flow
User --> appA["Application A <br> (Access for SaaS)"]
appA -- "Authorization: Bearer <token>" --> appB["Application B <br> (self-hosted)"]
idp[Identity provider] <--> appA
Create a policy on the self-hosted application (Application B):
-
In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Applications.
-
Select the self-hosted app (Application B) and select Edit.
-
Go to the Policies tab and select Create new policy.
-
Set the policy Action to Service Auth.
-
For Selector, select Linked App Token.
-
For Value, select the Access for SaaS app (Application A). For example,
Action Rule type Selector Value Service Auth Include Linked App Token application-a -
Save the policy.
-
In the self-hosted app (Application B), add the policy to the Access policies list.
-
Save the application.
-
Get the
uidof the Access for SaaS app (Application A):
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies RevokeAccess: Apps and Policies WriteAccess: Apps and Policies Read
List Access applications curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps" \--request GET \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"Response {"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","type": "saas","name": "my-saas-app",...} -
Create an Access policy on the downstream application, replacing the
app_uidvalue with theuidof the Access for SaaS app (Application A):
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies Write
Create an Access reusable policy curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/policies" \--request POST \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--json '{"name": "Allow requests from SaaS app","decision": "non_identity","include": [{"linked_app_token": {"app_uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}]}'
The SaaS application must forward the OAuth access_token to the self-hosted application in an HTTP header:
Authorization: Bearer ACCESS_TOKENThe end-to-end flow is:
- The user authenticates against the Access for SaaS app via OAuth.
- Upon success, the application receives an
access_token. - The application makes a request to the self-hosted application with the token in the
Authorization: Bearerheader. - Cloudflare Access inspects the token and validates it against the
linked_app_tokenrule. If valid, the request is allowed.
- The Linked App Token policy can only be added to self-hosted applications. It cannot be added to SaaS applications or other application types.
- This feature works best with applications that rely on the Cloudflare Access JWT for authentication and identity. If the downstream application implements its own authentication layer after Cloudflare Access, requests that pass Access validation may still be rejected by the application itself.