Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot exchange external OIDC ID token for Hydra access token due to aud claim handling in Hydra #3723

Open
3 of 5 tasks
davidallendj opened this issue Feb 28, 2024 · 1 comment
Labels
bug Something is not working.

Comments

@davidallendj
Copy link

davidallendj commented Feb 28, 2024

Preflight checklist

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:

  1. opaal initiates an authorization code flow by redirecting user to GitLab (assuming there's a registered client)

  2. User logs in and authorizes application with set scopes

  3. GitLab redirects back to opaal endpoint with code

  4. opaal makes another request back to GitLab with code to receive token (only interested in ID token)

  5. opaal fetches the JWKS from GitLab to include JWK in request to trust issuer

  6. The GitLab instance is added as a trusted issuer with the /admin/trust/grants/jwt-bearer/issuers endpoint

  7. A client is created/registered with Hydra with client ID, secret, and urn:ietf:params:oauth:grant-type:jwt-bearer grant type

  8. 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

  1. Register OAuth2 app with GitLab (or any OIDC identity provider??)

  2. Run opaal with appropriate configuration file

  3. Login and consent to app access scopes (returns code used by opaal)

  4. Observe output from opaal

Alternatively to running opaal, run the following instead after getting token:

  1. 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"]}'

  2. 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"]}'

  3. 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

@davidallendj davidallendj added the bug Something is not working. label Feb 28, 2024
@davidallendj
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is not working.
Projects
None yet
Development

No branches or pull requests

1 participant