OIDC client authentication
Let workloads on Kubernetes, Azure, GitLab CI or a tailnet authenticate as OIDC clients with tokens from their platform instead of a client secret.
A confidential client proves who it is when it calls the token endpoint, usually with its client secret. A secret is shared between the app and Pocket ID, so it has to be stored, rotated and kept from leaking, which is where most of its risk lies.
With federated client credentials, the client proves who it is with a token that its own platform issued instead, such as a Kubernetes service account token. Pocket ID trusts that token when its issuer, audience and subject match what you configured, so no long-lived secret exists at all:
The app needs to support JWT client assertions.
Instead of client_secret, it sends these two parameters to the token endpoint:
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearerclient_assertion=<token from the platform>Configure a client
Section titled “Configure a client”Open the client under Administration → OIDC Clients, go to its Credentials tab and click Add Federated Client Credential:
| Field | Description |
|---|---|
| Issuer | The iss claim of the platform’s tokens. Required. |
| Subject | The sub claim of the tokens. Defaults to the client ID. |
| Audience | The aud claim of the tokens. Defaults to your APP_URL. |
| Signing keys | Where Pocket ID gets the keys to verify the tokens: a JWKS URL, which defaults to <issuer>/.well-known/jwks.json, or Public keys you paste in. Use HTTPS for the JWKS URL. |
| Replay Protection | Accepts each token only once. Turn it off if the platform hands out the same token several times. |
A client can have several federated credentials, such as one per environment. The platforms below each need slightly different values.
Kubernetes service account tokens
Section titled “Kubernetes service account tokens”Using Kubernetes 1.21 or higher, you can use Projected Token Volumes to have the Kubernetes API server issue a token for the audience of your choice, and make it available to your app as projected volume.
Configuration values for using Kubernetes are:
- Issuer: Value of the Kubernetes’ API server’s issuer (this is generally passed as the value of the
--service-account-issuerflag forkube-apiserver). - Audience: Value of the
audienceoption specified when creating the Service Account for the Pod. While you can set this to any value, a good option is to use the public URL of Pocket ID. - Subject: The value is in the format
system:serviceaccount:<namespace>:<service-account-name>. E.g. for a ServiceAccount resource namedmy-sain the namespacemyappns, the value issystem:serviceaccount:myappns:my-sa. - JWKS URL (optional): The URL where the JWKS of the Kubernetes API server can be retrieved from. The default value is
<issuer>/.well-known/jwks.json.
Inside your application, you can obtain a JWT token to use as client assertion by reading the file where the projected token volume is mounted.
Additional resources:
- Kubernetes docs: Configure Service Accounts for Pods
- Kubernetes docs: Projected Volumes for
serviceAccountToken
Microsoft Azure
Section titled “Microsoft Azure”On Microsoft Azure, you can use Microsoft Entra Workload ID (e.g. Managed Identity or Workload Identity) to federate with Pocket ID.
Set up steps for Azure:
- Assign an identity to your application, such as a System-assigned or User-assigned Identity. Instructions are specific to each service being used.
- For workloads running on Azure Kubernetes Service, you may want to use Workload Identity
- Create an application in Microsoft Entra ID (docs)
- Take note of the client ID of this app, which will be a UUID
- Configure the Entra ID app with Federated credentials for the Managed Identity created for your resource (docs)
Configuration values for Federated Client Credentials in Pocket ID:
- Issuer:
https://sts.windows.net/<tenant-id>/where<tenant-id>is the UUID of your Microsoft Entra ID tenant - Audience: The client ID of the Entra ID application created above
- Subject: The object ID of the managed identity (note: this is the object (or principal) ID, not a client ID)
- JWKS URL: Constant value
https://login.microsoftonline.com/common/discovery/keys
Inside your application, you can obtain a token from the Managed Identity by:
- Recommended: using one of the Azure SDKs to get a token from Managed Identity, with the requested resource as the client ID of the Entra ID application. SDKs work on all Azure services automatically.
- Manually invoking the endpoint metadata service. The endpoint can be different depending on the Azure service; in the case of an Azure Virtual Machine, the URL is
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=<client-id>(where<client-id>is the client ID of the Entra ID application); make sure to also set the HTTP headerMetadata:truein the request.
Tailscale with tsiam
Section titled “Tailscale with tsiam”If your application is running on a node that is joined to a Tailscale network (“tailnet”), you can use the third-party tsiam application to provide workload identity.
When requesting a workload identity token from tsiam, it’s recommended to set as resource the endpoint of Pocket ID, for example https://pocketid.example.com
Configuration values for Federated Client Credentials in Pocket ID:
- Issuer: The URL of your tsiam instance inside the tailnet, for example
https://tsiam.tail<tailnet-id>.ts.net - Audience: The value of the resource used when requesting a token from tsiam; recommended to use the endpoint of Pocket ID (e.g.
https://pocketid.example.com) - Subject: The full name of the node in the tailnet, e.g.
<node-name>.tail<tailnet-id>.ts.net - JWKS URL: Leave empty to use the default value
GitLab CI
Section titled “GitLab CI”When running jobs in GitLab Pipelines, your job can authenticate as an OIDC client with Pocket ID using GitLab ID tokens.
Configuration values for Federated Client Credentials in Pocket ID:
- Issuer:
https://gitlab.com(or your self-hosted GitLab domain) - Audience:
https://pocketid.example.com- recommended to use the Pocket ID endpoint as the audience. - Subject:
project_path:my-group/my-project:ref_type:branch:ref:main- replacemy-group/my-projectwith the project you will be running the pipeline on. If working on a branch, changemainto your branch name. Currently, wildcards are not supported, so if you need to authenticate from pipelines running on different branches, you will need to create a Federated Client Credential for each branch. - JWKS URL:
https://gitlab.com/oauth/discovery/keys- if self-hosting, replacegitlab.com.
Here’s an example GitLab job that authenticates as an OIDC client:
example-job: image: alpine:3.23.3 id_tokens: GL_PIPELINE_TOKEN: aud: "$POCKET_ID_URL" # must match the `Audience` configured in Pocket ID. script: - apk update - apk add --no-cache curl jq - responsefile=$(mktemp) - | curl -SsfX POST --url "$POCKET_ID_URL/api/oidc/token" \ -F "grant_type=client_credentials" \ -F "client_id=$POCKET_ID_CLIENT_ID" \ -F "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \ -F "client_assertion=$GL_PIPELINE_TOKEN" \ -o "$responsefile" - access_token=$(jq '.access_token' -r < "$responsefile") - echo "Successfully obtained token with subject: client-$POCKET_ID_CLIENT_ID"The only variables you need to define are:
POCKET_ID_URL: The base URL of your pocket ID instance, such ashttps://pocketid.example.com. In the job above this URL is also used as the Audience of the Federated Client Credential.POCKET_ID_CLIENT_ID: the client ID of the OIDC Client configured in Pocket ID.
In the job above the client_credentials grant type is used, which means that the final token will have a subject of the form client-[client_id] (as opposed to a uuid identifying a user).