From simlu at su.se Fri Nov 6 10:25:50 2026 From: simlu at su.se (Simon =?utf-8?Q?Lundstr=C3=B6m?=) Date: Fri, 6 Nov 2026 11:25:50 +0100 Subject: OIDC: scoped sub with client_credentials? Message-ID: Hey all, We've been testing the waters with OIDC using both code flow and client_credentials (for M2M). I've read Scotts stern warning[1] so I don't wanna let this go before going to prod. Our strategy is basically go with using subject-id (i.e. eduPersonPrincipalName) and use the public subject type as the default. I have setup an OIDC RP using mod_auth_openidc using the authorization_code flow which gets sub scoped. How ever when I setup an OAuth2 Resource Server (aka API) and tried to authenticate a client using the client_credentials grant sub doesn't get scoped. I've used the provided examples and pasted in briefs below of what I think is relevant: RP with authorization_code grant which works: urn:mace:shibboleth:metadata:oidc:1.0:nameid-format:public Client which will talk to the OAuth2 Resource Server: urn:mace:shibboleth:metadata:oidc:1.0:nameid-format:public oidc-attribute-resolver.xml: oidc-attribute-filter.xml: Using authorization_code works: * Login to RP which shows scoped sub and via the access_token I can confirm it: $ curl -H "Authorization: Bearer $ACCESS_TOKEN" https://op.example.com/idp/profile/oidc/userinfo {"sub":"simlu at su.se","email_verified":true,"name":"Simon Lundstr?m","preferred_username":"simlu","given_name":"Simon","family_name":"Lundstr?m","email":"simlu at su.se"} Using client_credentials doesn't: $ curl -s -u "test-user:$CLIENT_SECRET" -d "grant_type=client_credentials" -d scope=openid 'https://op.example.com/idp/profile/oidc/token' | jq -r .access_token | jwt decode - [...] Token claims ------------ [...] "scope": "openid", "sub": "test-user" $ ACCESS_TOKEN=$(curl -s -u "test-user:$CLIENT_SECRET" -d "grant_type=client_credentials" -d scope=openid 'https://op.example.com/idp/profile/oidc/token' | jq -r .access_token) $ curl -s -H "Authorization: Bearer $ACCESS_TOKEN" https://op.example.com/idp/profile/oidc/userinfo {"sub":"test-user"} $ curl -s -u "test-user:$CLIENT_SECRET" -d "grant_type=client_credentials" 'https://op.example.com/idp/profile/oidc/token' | jq -r .access_token | jwt decode - [...] Token claims ------------ [...] "sub": "test-user" It feels like I'm missing something obvious. 1, Have a great weekend! BR, - Simon ____________________________________ Simon Lundstr?m IT Services Stockholm University SE-106 91 Stockholm, Sweden www.su.se/it https://www.su.se/english/about-this-website-1.517563