🚀 Feature: Custom scopes #207

Open
opened 2025-10-07 23:57:44 +03:00 by OVERLORD · 5 comments
Owner

Originally created by @zumoshi on GitHub.

Feature description

Currently pocket-id supports custom claims which is great. I've already used the custom claims to great success both in my own custom apps and in 3rd party applications.

However, all the claims are under the profile scope. I would like to be able to define custom scopes which show separately (same way Email/Profile do atm) while signing in to verify what info an app is asking for and isolate the claims to apps that need them.

Image

Pitch

I have two main reasons for wanting this.

  1. Reducing the size of resulting jwt, since most apps use the id_token as a cookie or header which is repeated on every request. if I use 10 apps and they each need a claim themselves they would need to resend data of the other 9 apps which they don't need on every request.
  2. Security concerns. from what I understand the JWT of id_token is signed with a global key, not a per oidc-client key. so an id_token generated while logging into one is valid for another. If one app had a security vulnerability (e.g. storing id_token in local storage as opposed to HTTP Only cookie and XSS), the leaked key could potentially be used on all other apps protected by pocket until it expires.

My specific case:
App 1 is a panel I made myself for management of a multi-user Caddy reverse proxy setup, and a claim has the filename for the user's caddyfile.
App 2 is a K3S instance, and uses a claim for RBAC to determine which role to assign to the logged in user.

I have a lot less trust in my own code than that of kubernetes, so I would prefer that the claim needed for K3S be missing from the JWT generated for my app. This could be achieved if I could add two scopes separate from profile, lets say scope caddy an scope kuber. then have each app request the respective one and verify while clicking sign in that I'm allowing the correct one.

Originally created by @zumoshi on GitHub. ### Feature description Currently pocket-id supports custom claims which is great. I've already used the custom claims to great success both in my own custom apps and in 3rd party applications. However, all the claims are under the profile scope. I would like to be able to define custom scopes which show separately (same way Email/Profile do atm) while signing in to verify what info an app is asking for and isolate the claims to apps that need them. ![Image](https://github.com/user-attachments/assets/40089fb4-d18f-4dc1-b73e-8d0a9516c87e) ### Pitch I have two main reasons for wanting this. 1. Reducing the size of resulting jwt, since most apps use the id_token as a cookie or header which is repeated on every request. if I use 10 apps and they each need a claim themselves they would need to resend data of the other 9 apps which they don't need on every request. 2. Security concerns. from what I understand the JWT of id_token is signed with a global key, not a per oidc-client key. so an id_token generated while logging into one is valid for another. If one app had a security vulnerability (e.g. storing id_token in local storage as opposed to HTTP Only cookie and XSS), the leaked key could potentially be used on all other apps protected by pocket until it expires. My specific case: App 1 is a panel I made myself for management of a multi-user Caddy reverse proxy setup, and a claim has the filename for the user's caddyfile. App 2 is a K3S instance, and uses a claim for RBAC to determine which role to assign to the logged in user. I have a lot less trust in my own code than that of kubernetes, so I would prefer that the claim needed for K3S be missing from the JWT generated for my app. This could be achieved if I could add two scopes separate from profile, lets say scope caddy an scope kuber. then have each app request the respective one and verify while clicking sign in that I'm allowing the correct one.
OVERLORD added the breaking label 2025-10-07 23:57:44 +03:00
Author
Owner

@zumoshi commented on GitHub:

Interesting read. Thanks for sharing, I'll keep that in mind when implementing OIDC on my own code.

However, I have no control over how Kubernetes has implemented it:

To identify the user, the authenticator uses the id_token (not the access_token) from the OAuth2 token response as a bearer token.

They are clearly violating this phrase from your link:

ID tokens should never be sent to an API. Access tokens should never be read by the client.

Since with kubelogin the oauth happens on client side completely, only the id_token being sent their way. the config for setting up the OIDC doesn't even ask for the secret, instead you provide that to the client!

I still think there is merit for having separate scopes, even if the openId client is more compliant with the specs tho.

@zumoshi commented on GitHub: Interesting read. Thanks for sharing, I'll keep that in mind when implementing OIDC on my own code. However, I have no control over how [Kubernetes](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) has implemented it: > To identify the user, the authenticator uses the id_token (not the access_token) from the OAuth2 [token response](https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse) as a bearer token. They are clearly violating this phrase from your link: > ID tokens should never be sent to an API. Access tokens should never be read by the client. Since with [kubelogin](https://github.com/int128/kubelogin) the oauth happens on client side completely, only the id_token being sent their way. the config for setting up the OIDC doesn't even ask for the secret, instead you provide that to the client! I still think there is merit for having separate scopes, even if the openId client is more compliant with the specs tho.
Author
Owner

@kmendell commented on GitHub:

@Impre-visible It would have to be in 2.0.0 as it would be a breaking change, sure we could add a whol bunch of migration logic but thats just not maintainable for us now and in the future.

@kmendell commented on GitHub: @Impre-visible It would have to be in 2.0.0 as it would be a breaking change, sure we could add a whol bunch of migration logic but thats just not maintainable for us now and in the future.
Author
Owner

@Impre-visible commented on GitHub:

I'm bumping that feature as it can be awesome, and I'm down to work on it and make it appear before the v2.0.0 👍

@Impre-visible commented on GitHub: I'm bumping that feature as it can be awesome, and I'm down to work on it and make it appear before the v2.0.0 👍
Author
Owner

@ItalyPaleAle commented on GitHub:

Not the thing you asked for, but...

id_tokens are not meant to be used to maintain a session: https://oauth.net/id-tokens-vs-access-tokens/

From what I understand the JWT of id_token is signed with a global key, not a per oidc-client key. so an id_token generated while logging into one is valid for another.

That's what the aud claim should be for. In Pocket ID (per OAuth specs), access tokens and ID tokens have the client ID of the app as value for aud https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3

@ItalyPaleAle commented on GitHub: Not the thing you asked for, but... id_tokens are not meant to be used to maintain a session: https://oauth.net/id-tokens-vs-access-tokens/ > From what I understand the JWT of id_token is signed with a global key, not a per oidc-client key. so an id_token generated while logging into one is valid for another. That's what the `aud` claim should be for. In Pocket ID (per OAuth specs), access tokens and ID tokens have the client ID of the app as value for `aud` https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3
Author
Owner

@ItalyPaleAle commented on GitHub:

I still think there is merit for having separate scopes, even if the openId client is more compliant with the specs tho.

I agree

@ItalyPaleAle commented on GitHub: > I still think there is merit for having separate scopes, even if the openId client is more compliant with the specs tho. I agree
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/pocket-id-pocket-id-1#207