🚀 Feature: Support private_key_jwt client authentication method per RFC7523 (Security) #284

Closed
opened 2025-10-07 00:08:50 +03:00 by OVERLORD · 12 comments
Owner

Originally created by @ItalyPaleAle on GitHub.

Feature description

RFC7523 describes authenticating clients using a JWT, signed by a third-party, instead of a client secret.

In the case most applicable to Pocket ID, this would be used as part of the Authorization Code flow when invoking the /token endpoint.

When making a call to the /token endpoint with grant_type=authorization_code, instead of including a client_secret, callers include two more parameters:

  • client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer (this is a constant)
  • client_assertion=... value is a JWT issued by a third-party with some requirements as specified in section 3 or the RFC

The identity server uses the assertions passed by the client to validate their identity instead of a pre-shared client secret.

From a technical standpoint, this requires making Pocket ID accept for each client (app) a list of identity providers that are authorized to sign tokens to prove the clients' identities.

Eventually, the goal is to make it possible to use things such as managed identities when running in cloud environments, workload identity on K8s, or SPIFFE.

Links:

Pitch

Secrets are bad for security. It takes a lot of education to teach users how to handle them properly, and even then people misplaces secrets all the time. Just one data point: in 2022, researchers found 10 million secrets in GitHub repositories.

Even when users do all things right, secrets are often stored somewhere in plain text, which makes them susceptible to leaking in other ways.

The industry is moving away from secrets in general. For example, at Microsoft where I used to work, in 2024 there was a massive effort to get rid of all shared secrets from applications, using other solutions including managed identities instead. External users were encouraged to do the same.

Popular examples include support for OIDC in GitHub Actions, which is widely used already: https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments

Originally created by @ItalyPaleAle on GitHub. ### Feature description RFC7523 describes authenticating clients using a JWT, signed by a third-party, instead of a client secret. In the case most applicable to Pocket ID, this would be used as part of the Authorization Code flow when invoking the `/token` endpoint. When making a call to the `/token` endpoint with `grant_type=authorization_code`, instead of including a `client_secret`, callers include two more parameters: - `client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer` (this is a constant) - `client_assertion=...` value is a JWT issued by a third-party with some requirements as specified in [section 3 or the RFC](https://datatracker.ietf.org/doc/html/rfc7523#section-3) The identity server uses the assertions passed by the client to validate their identity instead of a pre-shared client secret. From a technical standpoint, this requires making Pocket ID accept for each client (app) a list of identity providers that are authorized to sign tokens to prove the clients' identities. Eventually, the goal is to make it possible to use things such as managed identities when running in cloud environments, workload identity on K8s, or SPIFFE. Links: - RFC 7523: https://datatracker.ietf.org/doc/html/rfc7523 - Sample from the Authlete docs: https://www.authlete.com/kb/oauth-and-openid-connect/client-authentication/client-auth-private-key-jwt/ - Discussion in Keycloak: https://github.com/keycloak/keycloak/discussions/14823 - Docs from Okta: https://developer.okta.com/docs/api/openapi/okta-oauth/guides/client-auth/#jwt-with-private-key ### Pitch **Secrets are bad for security**. It takes a lot of education to teach users how to handle them properly, and even then people misplaces secrets all the time. Just one data point: in 2022, [researchers found](https://www.gitguardian.com/files/the-state-of-secrets-sprawl-report-2023) 10 million secrets in GitHub repositories. Even when users do all things right, secrets are often stored _somewhere_ in plain text, which makes them susceptible to leaking in other ways. The industry is moving away from secrets in general. For example, at Microsoft where I used to work, in 2024 there was a massive effort to get rid of all shared secrets from applications, using other solutions including managed identities instead. External users were encouraged to do the same. Popular examples include support for OIDC in GitHub Actions, which is widely used already: https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments
OVERLORD added the feature label 2025-10-07 00:08:50 +03:00
Author
Owner

@ItalyPaleAle commented on GitHub:

the key chnage you are wanting to see is client secret replaces wit ha JWT private key? or both to exsist?

Both will continue to exist. We can't deprecate client secrets because a lot of code depends on them. They'll probably continue to exist "forever".

Client secrets could be made optional (apps may not have a secret at all), but even making it so clients don't need to use a client secret can be helpful.

From all the OIDC providers ive seen the yall still use secrets

All providers still offer support for client secrets. That's a required part of the OAuth2 spec, so they can't remove them. Neither should we.

What's more interesting is providers that offer support for flows that don't involve client secrets. Azure AD, Auth0, and Okta are providers that I know for sure support this.

@ItalyPaleAle commented on GitHub: > the key chnage you are wanting to see is client secret replaces wit ha JWT private key? or both to exsist? Both will continue to exist. We can't deprecate client secrets because a lot of code depends on them. They'll probably continue to exist "forever". Client secrets _could_ be made optional (apps may not have a secret at all), but even making it so clients don't need to use a client secret can be helpful. > From all the OIDC providers ive seen the yall still use secrets All providers still offer support for client secrets. That's a required part of the OAuth2 spec, so they can't remove them. Neither should we. What's more interesting is providers that offer support for flows that _don't_ involve client secrets. Azure AD, Auth0, and Okta are providers that I know for sure support this.
Author
Owner

@kmendell commented on GitHub:

"Eventually, the goal is to make it possible to use things such as managed identities when running in cloud environments, workload identity on K8s, or SPIFFE."

Is the primary purpose of this for Kubernetes? If so we dont officially support kubernetes so if this change soley inly is used in those environments, then im not sure it would make sense. Im just guessing im not sure as i havent read the linked docs yet.

I do like some of the points made though , i need to read through the linked doumentation to understand more though.

@kmendell commented on GitHub: "Eventually, the goal is to make it possible to use things such as managed identities when running in cloud environments, workload identity on K8s, or SPIFFE." Is the primary purpose of this for Kubernetes? If so we dont officially support kubernetes so if this change soley inly is used in those environments, then im not sure it would make sense. Im just guessing im not sure as i havent read the linked docs yet. I do like some of the points made though , i need to read through the linked doumentation to understand more though.
Author
Owner

@kmendell commented on GitHub:

I guess i missed the commas :P my bad!

@kmendell commented on GitHub: I guess i missed the commas :P my bad!
Author
Owner

@ItalyPaleAle commented on GitHub:

Is the primary purpose of this for Kubernetes?

No, I listed 3 examples:

@ItalyPaleAle commented on GitHub: > Is the primary purpose of this for Kubernetes? No, I listed 3 examples: - Running in cloud providers. For example, Azure has Managed Identity: https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview - SPIFFE is a CNCF standard that's platform and cloud-agnostic - K8s does issue tokens too that could be used
Author
Owner

@kmendell commented on GitHub:

So overall the key chnage you are wanting to see is client secret replaces wit ha JWT private key? or both to exsist?

From all the OIDC providers ive seen the yall still use secrets Authentik, Autheila, even SaSS like Entra still give client secrets. Thoguh the managed identities (i think your referring to) if it is entra, all auth has to be inside of azure (unless stuff has chnaged since i last looked into Azure/Entra)

@kmendell commented on GitHub: So overall the key chnage you are wanting to see is client secret replaces wit ha JWT private key? or both to exsist? From all the OIDC providers ive seen the yall still use secrets Authentik, Autheila, even SaSS like Entra still give client secrets. Thoguh the managed identities (i think your referring to) if it is entra, all auth has to be inside of azure (unless stuff has chnaged since i last looked into Azure/Entra)
Author
Owner

@kmendell commented on GitHub:

Okay thats what i thought , but i wanted to confirm to make sure i wasnt reading your issue wrong.

If you dont mind, so i can undrstand better, Can you provide a hgih level example flow that is used with this? im just curious i know you include that diagram but i was thinking more of a example if you have one.

@kmendell commented on GitHub: Okay thats what i thought , but i wanted to confirm to make sure i wasnt reading your issue wrong. If you dont mind, so i can undrstand better, Can you provide a hgih level example flow that is used with this? im just curious i know you include that diagram but i was thinking more of a example if you have one.
Author
Owner

@ItalyPaleAle commented on GitHub:

It's the regular OAuth2 Authorization Code flow: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow

There's only 1 modification when invoking the /token endpoint to exchange an atuh code for an access token. For confidential clients, instead of providing a client_secret, they provide a client_assertion which includes a JWT signed by another authority.

How that assertion is obtained is outside of the scope of Pocket ID. It could come from SPIFFE, another IdP, some cloud provider managed identity, etc.

@ItalyPaleAle commented on GitHub: It's the regular OAuth2 Authorization Code flow: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow There's only 1 modification when invoking the `/token` endpoint to exchange an atuh code for an access token. For confidential clients, instead of providing a client_secret, they provide a client_assertion which includes a JWT signed by another authority. _How that assertion is obtained is outside of the scope of Pocket ID_. It could come from SPIFFE, another IdP, some cloud provider managed identity, etc.
Author
Owner

@kmendell commented on GitHub:

okay i think i get it now, based on the reading, i think this should be able to be implemented without thats much work.

@stonith404 What are you thoughts?

@kmendell commented on GitHub: okay i think i get it now, based on the reading, i think this should be able to be implemented without thats much work. @stonith404 What are you thoughts?
Author
Owner

@ItalyPaleAle commented on GitHub:

at some point I would welcome Yubikey (PKCS #11) support

I assume you mean for storing the "private key" used by Pocket ID to sign tokens? The next proposal I was working on was support for storing the private key on other places (I am specifically interested in Azure Key Vault, AWS KMS, etc), and PKCS#11 does fit into that space.

That's for a different kind of problem however. In this issue I'm more focused on secret keys that are given to applications (clients), and which are notoriously cause for headaches among developers (even more experienced ones).

@ItalyPaleAle commented on GitHub: > at some point I would welcome Yubikey (PKCS #11) support I assume you mean for storing the "private key" used by Pocket ID to sign tokens? The next proposal I was working on was support for storing the private key on _other places_ (I am specifically interested in Azure Key Vault, AWS KMS, etc), and PKCS#11 does fit into that space. That's for a different kind of problem however. In this issue I'm more focused on secret keys that are given to applications (clients), and which are notoriously cause for headaches among developers (even more experienced ones).
Author
Owner

@savely-krasovsky commented on GitHub:

To be honest I would even pitch for FAPI compliance at some point. I think Pocket-ID can be yet simple, but at the same time offer optional advanced security. @ItalyPaleAle is already working on a various JWK types, at some point I would welcome Yubikey (PKCS #11) support, for example. So I am definitely in.

@savely-krasovsky commented on GitHub: To be honest I would even pitch for FAPI compliance at some point. I think Pocket-ID can be yet simple, but at the same time offer optional advanced security. @ItalyPaleAle is already working on a various JWK types, at some point I would welcome Yubikey (`PKCS #11`) support, for example. So I am definitely in.
Author
Owner

@kmendell commented on GitHub:

I assume you mean for storing the "private key" used by Pocket ID to sign tokens? The next proposal I was working on was support for storing the private key on other places (I am specifically interested in Azure Key Vault, AWS KMS, etc), and PKCS#11 does fit into that space.

This may be getting into territory that i think is out of scope of pocket id. As that's is for sure a niche use case. Most user would have no idea how to use that, in my honest opinion.

Just a global note, Pocket ID is still technically "Early Access" Software, Once 1.0 releases there may be much more room for certain enhancement features.

@kmendell commented on GitHub: > I assume you mean for storing the "private key" used by Pocket ID to sign tokens? The next proposal I was working on was support for storing the private key on _other places_ (I am specifically interested in Azure Key Vault, AWS KMS, etc), and PKCS#11 does fit into that space. This may be getting into territory that i think is out of scope of pocket id. As that's is for sure a niche use case. Most user would have no idea how to use that, in my honest opinion. Just a global note, Pocket ID is still technically "Early Access" Software, Once 1.0 releases there may be much more room for certain enhancement features.
Author
Owner

@ItalyPaleAle commented on GitHub:

We can park the conversation on external keys for now!

It's out of scope from this issue anyways, which is focused on making it possible for clients to work without a client_secret

@ItalyPaleAle commented on GitHub: We can park the conversation on external keys for now! It's out of scope from this issue anyways, which is focused on making it possible for clients to work without a client_secret
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/pocket-id#284