hydra icon indicating copy to clipboard operation
hydra copied to clipboard

oauth2 webhook: `granted_scopes` always empty

Open dastein1 opened this issue 2 years ago • 7 comments

Preflight checklist

Ory Network Project

No response

Describe the bug

The documentation outlines that the webhok should receive request-details.
The request has a field called granted_scopes, but it's always an empty list instead of the granted scopes by the consent application.

{
  ...
  "request": {
    "client_id": "some-client-id",
    "granted_scopes": [],                  // <- THIS IS ALWAYS EMPTY
    "granted_audience": [],
    "grant_types": [
      "authorization_code"
    ],
    "payload": {}
  }
}

Previous slack discussions around this topic:

  • https://archive.ory.sh/t/13537419/hi-all-im-currently-trying-out-https-www-ory-sh-docs-hydra-g
  • https://archive.ory.sh/t/14170318/hi-i-was-wondering-if-there-s-a-possibility-to-get-the-grant

Reproducing the bug

Clone hydra

git clone https://github.com/ory/hydra.git
cd hydra

Run server

enable the token_hook in contrib/quickstart/5-min/hydra.yml have this token_hook log the request

oauth2:
  token_hook: http://host.docker.internal:1323
docker-compose -f quickstart.yml \
 -f quickstart-postgres.yml \
 -f quickstart-tracing.yml \
 up --build

Create client and run auth code flow

Note: accept at least 1 of the scopes

code_client=$(docker-compose -f quickstart.yml exec hydra \
    hydra create client \
    --endpoint http://127.0.0.1:4445 \
    --grant-type authorization_code,refresh_token \
    --response-type code,id_token \
    --format json \
    --scope openid --scope offline \
    --redirect-uri http://127.0.0.1:5555/callback)

code_client_id=$(echo $code_client | jq -r '.client_id')
code_client_secret=$(echo $code_client | jq -r '.client_secret')

docker-compose -f quickstart.yml exec hydra \
 hydra perform authorization-code \
 --client-id $code_client_id \
 --client-secret $code_client_secret \
 --endpoint http://127.0.0.1:4444/ \
 --port 5555 \
 --scope openid --scope offline

Check

In the request that the token_hook receives. The request.grant_types remains empty.

Relevant log output

No response

Relevant configuration

oauth2:
  token_hook: http://host.docker.internal:1323

Version

oryd/hydra:v2.2.0-rc.3

On which operating system are you observing this issue?

None

In which environment are you deploying?

None

Additional Context

  • Issue also present on master
  • Not related to OS or deployment

dastein1 avatar Aug 25 '23 12:08 dastein1

I'm having the same issue in v2.1.1. Running the project locally, I can see that the hook is executed before the requester is granted any scopes (https://github.com/ory/hydra/blob/89b1b1bd35d7d906b8cf9048dcc34d416aa3a9b0/oauth2/handler.go#L1005-L1020) which is according to the docs.

Thing is, during the authorization_code flow when the webhook handler calls requester.GetGrantedScopes() no scope was granted yet.

@aeneasr Do you see any problems in running the hook after the internal logic is executed (i.e after the NewAccessResponse(ctx, accessRequest) call)? In this scenario I think the begin/commit of the transactions that invalidates the refresh and authorization code in the database needs to be moved to the outer scope (will need changes in ory/fosite too). Alternatively, what are you thoughts in using the requester.RequestedScopes() instead of requester.GrantedScopes() in this case?

yanuehara-mb avatar Oct 03 '23 17:10 yanuehara-mb

@aeneasr any thoughts on that?

dastein1 avatar Oct 19 '23 12:10 dastein1

Hi, we are having the same issue, would you have any updates please ? @hperl @dastein1 @aeneasr We are running on v2.1.2

jossbnd avatar Dec 18 '23 16:12 jossbnd

Unfortunately there's still no feedback from the core team. I brought that topic up on slack twice but it did not lead anywhere (@hperl @aeneasr @kmherrmann).

For the time being, I have worked around that problem by only doing stuff in the token-hook that does not depend on the granted_scopes and the rest within the consent application (although that means to duplicate some functionality between services).

dastein1 avatar Jan 15 '24 11:01 dastein1

Same here! After accepting the consent request with the given Parameters (grantScopes included) the request details remains empty:

public String acceptConsentRequest(Map<String, Object> idToken, List<String> grantScopes, String consentChallenge) {
        AcceptConsentRequest consentRequest = new AcceptConsentRequest();
        consentRequest.setRemember(true);
        // If set to '0', the authorization will be remembered indefinitely.
        consentRequest.setRememberFor(0L);
        consentRequest.setGrantScope(grantScopes);
        AcceptConsentRequestSession session = new AcceptConsentRequestSession();
        session.setIdToken(idToken);
        consentRequest.setSession(session);
        ResteasyWebTarget target = getWebTargetInstance();
        Response response = target.proxy(OAuthProxy.class).acceptConsentRequest(consentChallenge, consentRequest);
        if (response.getStatus() == Response.Status.OK.getStatusCode()) {
            CompletedRequest completedRequest = response.readEntity(new GenericType<CompletedRequest>() {
            });
            if (completedRequest != null) {
                return completedRequest.getRedirectTo();
            }
        }
        return null;
    }

The redirect URI looks as follows:

https://localhost:9000/oauth2/auth?client_id=084c2a4e-de40-4537-8cdd-9a0c937acde3&consent_verifier=6eb972e5b86743bd96f86dbabef2c6b5&redirect_uri=http%3A%2F%2Flocalhost%3A2003&response_type=code&scope=openid+email&state=ur_kol1shpflj8h95snqnh1d8halg

Calling the URL will provide this:

{
    "session": {
        "id_token": {
            "id_token_claims": {
                "jti": "",
                "iss": "https://localhost:9000/",
                "sub": "[email protected]",
                "aud": [
                    "084c2a4e-de40-4537-8cdd-9a0c937acde3"
                ],
                "nonce": "",
                "exp": "0001-01-01T00:00:00Z",
                "iat": "2024-08-14T12:26:25Z",
                "rat": "2024-08-14T12:26:13Z",
                "auth_time": "2024-08-14T11:38:40Z",
                "at_hash": "",
                "acr": "",
                "amr": [
                ],
                "c_hash": "",
                "ext": {
                    "email": "[email protected]",
                    "email_verified": true,
                    "given_name": "Hansen",
                    "name": "Hansen Pansen",
                    
                }
            },
            "headers": {
                "extra": {
                    "kid": "b932e971-a105-4151-927c-6e8759ce6881"
                }
            },
            "expires_at": {
                "access_token": "2024-08-14T13:26:26Z",
                "authorize_code": "2024-08-14T12:36:25.561520554Z",
                "refresh_token": "2024-09-13T12:26:26Z"
            },
            "username": "",
            "subject": "[email protected]"
        },
        "extra": {
        },
        "kid": "",
        "client_id": "084c2a4e-de40-4537-8cdd-9a0c937acde3",
        "consent_challenge": "6a70d27d82cb460cb5ff6c301a877555",
        "exclude_not_before_claim": false,
        "allowed_top_level_claims": [
        ]
    },
    "request": {
        "client_id": "084c2a4e-de40-4537-8cdd-9a0c937acde3",
        "granted_scopes": [
        ],
        "granted_audience": [
        ],
        "grant_types": [
            "authorization_code"
        ],
        "payload": {
        }
    }
}

As you can see, the "granted_scopes" are empty.

vmuth85 avatar Aug 14 '24 12:08 vmuth85

I've spent some time on investigation and here are my notes:

  • granted_scopes as well granted_auidience is always empty
  • even though consent is approved it does not work for authorization_code grant type
  • if you try refresh_token grant type, granted_scopes as well granted_auidience is properly populated

We were using kratos-selfservice-ui-node to provide consent screen and we were skipping consent, so all grants and scope were passed through and accepted.

dfilicko-at-pacellico avatar Aug 16 '24 12:08 dfilicko-at-pacellico