hydra
hydra copied to clipboard
Cannot exchange external OIDC ID token for Hydra access token due to `aud` claim handling in Hydra
Preflight checklist
- [X] I could not find a solution in the existing issues, docs, nor discussions.
- [X] I agree to follow this project's Code of Conduct.
- [X] I have read and am following this repository's Contribution Guidelines.
- [ ] I have joined the Ory Community Slack.
- [ ] I am signed up to the Ory Security Patch Newsletter.
Ory Network Project
No response
Describe the bug
Trying to acquire an access token from Hydra using the urn:ietf:params:oauth:grant-type:jwt-bearer
grant type fails when including an JWT from GitLab as the identity provider when making a request to the /oauth2/token
. The intent is to receive an ID token through social sign-in with GitLab and then have Hydra respond with an access token upon successful verification of the JWT. I was basically following the docs for using JWTs as authorization grants. This process is automated with a custom tool called opaal
.
The entire flow is broken down as follows:
-
opaal
initiates an authorization code flow by redirecting user to GitLab (assuming there's a registered client) -
User logs in and authorizes application with set scopes
-
GitLab redirects back to
opaal
endpoint with code -
opaal
makes another request back to GitLab with code to receive token (only interested in ID token) -
opaal
fetches the JWKS from GitLab to include JWK in request to trust issuer -
The GitLab instance is added as a trusted issuer with the
/admin/trust/grants/jwt-bearer/issuers
endpoint -
A client is created/registered with Hydra with client ID, secret, and
urn:ietf:params:oauth:grant-type:jwt-bearer
grant type -
Request is made to
/oauth2/token
endpoint with grant type, client ID, and assertion
The expected output is another token from Hydra, but Hydra is complaining about the token having the wrong audience (see error below), which I believe is the intended behavior according to section 3.3 of RFC 7523 and the OpenID documentation. How would you go about using a JWT from another OIDC provider with Hydra if the provider sets the audience to something other than the intended token endpoint for Hydra?
Reproducing the bug
-
Register OAuth2 app with GitLab (or any OIDC identity provider??)
-
Run
opaal
with appropriate configuration file -
Login and consent to app access scopes (returns code used by
opaal
) -
Observe output from
opaal
Alternatively to running opaal
, run the following instead after getting token:
-
Add trusted issuer:
curl http://127.0.0.1:4445/admin/trust/grants/jwt-bearer/issuers -X POST -H 'Content-Type: application/json' -d '{"allow_any_subject": false, "issuer": "https://gitlab.com", "subject": "1", "expires_at": "2025-01-01 12:00:00", "jwk": "$jwk", "scope": ["openid", "profile", "email"]}'
-
Register new client:
curl http://127.0.0.1:4444/oauth2/client -X POST -H 'Content-Type: application/json' -d '{"client_name": "opaal", "token_endpoint_auth_method": "client_secret_post", "scope": "openid email profile", "grant_types": ["client_credentials", "urn:ietf:params:oauth:grant-type:jwt-bearer"], "response_type": ["token"]}'
-
Make a request for a token:
curl http://127.0.0.1:4444/oauth2/token -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&client_id=43b425a7-c687-4e20-92d0-c5f6ca81631e&client_secret=gloas-d478a49ce2e99a03f37d4324aa68832fbfb9d0712f92493c42a5db13b4540299&scope=openid+profile+email&assertion=${jwt}'
Relevant log output
{
"error": "invalid_grant",
"error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. The JWT in assertion request parameter MUST contain an aud (audience) claim containing a value http://127.0.0.1:4444/oauth2/token that identifies the authorization server as an intended audience."
}
Relevant configuration
# Hydra config:
serve:
cookies:
same_site_mode: Lax
names:
login_csrf: login
consent_csrf: consent
session: session
urls:
self:
issuer: http://127.0.0.1:4444
consent: http://127.0.0.1:4455/consent
login: http://127.0.0.1:4455/login
logout: http://127.0.0.1:4455/logout
secrets:
system:
- <REDACTED>
oidc:
dynamic_client_registration:
enabled: true
subject_identifiers:
supported_types:
- pairwise
- public
pairwise:
salt: <REDACTED>
oauth2:
grant:
jwt:
jti_optional: true
iat_optional: true
max_ttl: 1h
log:
leak_sensitive_values: true
# Docker compose
version: "3.7"
networks:
internal:
external:
external: true
volumes:
hydra-sqlite:
services:
hydra:
image: oryd/hydra:v2.2.0
container_name: hydra
ports:
- "4444:4444" # Public port
- "4445:4445" # Admin port
- "5555:5555" # Port for hydra token user
command: serve -c /etc/config/hydra/hydra.yml all --dev
volumes:
- type: volume
source: hydra-sqlite
target: /var/lib/sqlite
read_only: false
- type: bind
source: ./configs/hydra
target: /etc/config/hydra
environment:
- DSN=sqlite:///var/lib/sqlite/db.sqlite?_fk=true
restart: unless-stopped
depends_on:
- hydra-migrate
networks:
- internal
hydra-migrate:
image: oryd/hydra:v2.2.0
environment:
- DSN=sqlite:///var/lib/sqlite/db.sqlite?_fk=true
command: migrate -c /etc/config/hydra/hydra.yml sql -e --yes
volumes:
- type: volume
source: hydra-sqlite
target: /var/lib/sqlite
read_only: false
- type: bind
source: ./configs/hydra
target: /etc/config/hydra
restart: on-failure
networks:
- internal
consent:
environment:
- HYDRA_ADMIN_URL=http://hydra:4445
image: oryd/hydra-login-consent-node:v2.2.0
ports:
- "3001:3001"
restart: unless-stopped
networks:
- internal
# Opaal's config:
server:
host: 127.0.0.1
port: 3333
client:
id: <REDACTED> # from GitLab applications
secret: <REDACTED> # from GitLab applications
redirect-uris:
- "http://127.0.0.1:3333/oidc/callback"
oidc:
issuer: "https://gitlab.com"
urls:
#identities: http://127.0.0.1:4434/admin/identities
trusted-issuers: http://127.0.0.1:4445/admin/trust/grants/jwt-bearer/issuers
access-token: http://127.0.0.1:4444/oauth2/token
server-config: https://gitlab.com/.well-known/openid-configuration
jwks_uri: https://gitlab.com/oauth/discovery/keys
login: http://127.0.0.1:4433/self-service/login/api
login-flow-id: http://127.0.0.1:4433/self-service/login/flows?id={id}
state: ""
response-type: code
decode-id-token: true
decode-access-token: true
run-once: true
scope:
- openid
- profile
- email
Version
2.2.0
On which operating system are you observing this issue?
macOS
In which environment are you deploying?
Docker Compose
Additional Context
No response
Editted links and formatting
Just to add, something like RFC 8707 should make what I'm trying to do possible, but I think that would have to be implemented on the identity provider side (in this case GitLab) to specify the intended audience.