How does internal service auth work with default Authorizer/Claim Mapper?

Hello,

I’m trying to enable authentication and authorization using the default authorizer and default claim mapper in a Temporal deployment, but internal services are failing to authorize.

Setup

  • Image: temporalio/server:1.29 (stock image)

  • Config:

    - TEMPORAL_AUTH_AUTHORIZER=default
    - TEMPORAL_AUTH_CLAIM_MAPPER=default
    

When these are enabled the service worker crashes with Request unauthorized. It appears that the built-in services (history, matching, worker, etc.) do not send JWTs by default, so their requests arrive without claims and are rejected by the default authorizer.

Question

How do I make Temporal’s built-in services authorize successfully with the default authorizer and default claim mapper?

Any examples from others who’ve configured this successfully would be greatly appreciated. :smiley:

Okay, so I’ve come up with a solution myself:

Apparently there is this internal-frontend feature added in version 1.20.0 that allows you to use the default Authorizer and default Claims Mapper while allowing the deployment to differentiate between the system worker service and external clients. This solves the need for the worker service to attach it’s own JWT when calling the frontend.

The part that tripped me up: USE_INTERNAL_FRONTEND=true only affects the rendered config; it does not start the process. The container only launches what’s listed in SERVICES, and when that variable is unset it defaults to frontend:history:matching:worker. In other words, no internal-frontend unless you ask for it explicitly.

What worked for me was adding:

- USE_INTERNAL_FRONTEND=true
- SERVICES=frontend:history:matching:worker:internal-frontend

After redeploying, internal-frontend started, the worker stopped getting “Request unauthorized,” and the default authorizer + claim mapper behaved as expected with my JWKS config. If you want to double‑check, look for services.internal-frontend in config/docker.yaml and confirm the logs show it initializing rather than being skipped.