Problems with completing Authorization Code Flow only through API requests, no front-end

Hi

I am trying to implement ORY Hydra into my project security flow.
The project consists of a client making requests to an API, and I want to increase the security by including an access token with every request to that API and validating the tokens through the Hydra token introspection endpoint.

The difficult part for me is getting ORY Hydra to issue authorization tokens, and I have a few questions.
First of all - I’ve been testing to see if backend-to-backend OAuth with Hydra is even a possibility. I’ve tried this by sending requests to the respective /oauth2/auth/* endpoints and parsing the responses.

  1. is there a better way of going about implementing this? Sending these “pseudo”-requests seems rudimentary…
  2. can the “subject” in /oauth2/auth/requests/login/accept endpoint be a string generated by the client who is trying to get the authorization code from Hydra?
  3. after sending a request to /oauth2/auth/requests/consent/accept endpoint, I get a “redirect_to” link in the response body. By sending another GET request to that url (/oauth2/auth?client_id=xxxxx&consent_verifier=xxxxx&response_type=code&scope=offline&state=xxxxx), I expect to get the authorization code, but I don’t…

Looking at Hydra logs, there doesn’t seem to be anything wrong with the request:

hydra_1 | time=“2019-11-21T14:36:01Z” level=info msg=“started handling request” method=GET remote=“172.20.0.1:34300” request="/oauth2/auth?client_id=auth123&response_type=code&scope=offline&redirect_uri=http://localhost:5555/callback&consent_verifier=d39f7c1e713940fb964ea6e2031a0a69&state=123456789"
hydra_1 | time=“2019-11-21T14:36:01Z” level=info msg=“completed handling request” measure#hydra/public: http://127.0.0.1:4444/.latency=16166800 method=GET remote=“172.20.0.1:34300” request="/oauth2/auth?client_id=xxxxx&response_type=code&scope=offline&redirect_uri=http://localhost:5555/callback&consent_verifier=xxxxx&state=xxxxx" status=302 text_status=Found took=16.1668ms

The Postman response does not give any information either:

Could not get any response
There was an error connecting to /oauth2/auth?client_id=xxxxx&response_type=code&scope=offline&redirect_uri=http://localhost:5555/callback&consent_verifier=xxxxx&state=xxxxx.

Any answers to my questions are greatly appreciated.

The difficult part for me is getting ORY Hydra to issue authorization tokens, and I have a few questions.
First of all - I’ve been testing to see if backend-to-backend OAuth with Hydra is even a possibility. I’ve tried this by sending requests to the respective /oauth2/auth/* endpoints and parsing the responses.
is there a better way of going about implementing this? Sending these “pseudo”-requests seems rudimentary…

OAuth2 is usually overkill for first-party applications. I’m not sure if you would benefit from it. A better bet might be github.com/ory/kratos (not yet released but hopefully until the end of the year)

can the “subject” in /oauth2/auth/requests/login/accept endpoint be a string generated by the client who is trying to get the authorization code from Hydra?

No, that would leave you open to tons of attack vectors, including impersonation.

after sending a request to /oauth2/auth/requests/consent/accept endpoint, I get a “redirect_to” link in the response body. By sending another GET request to that url (/oauth2/auth?client_id=xxxxx&consent_verifier=xxxxx&response_type=code&scope=offline&state=xxxxx), I expect to get the authorization code, but I don’t…

Could it be possible that the “redirect url” (http://localhost:5555/callback) you have set up is broken? Some http clients show broken redirects as an error with the original url.

Could it be possible that the “redirect url” (http://localhost:5555/callback) you have set up is broken? Some http clients show broken redirects as an error with the original url.

Yes, it appears that was the issue with this part.

Now that the redirect_uri is fixed, the response directs me to the page with the tokens, but at no point did I see the authorization_code param. How is the authorization code generated and how does Hydra validate it? Is it set as another parameter with a different name?

Thanks for the reply @hackerman!

Not sure I understand the question :slight_smile: Can you include the full “end” url? So something like http://localhost:5555/callback?..... Maybe an error occurred or something.

Okay, so first of all, I start the example web server, as per the tutorial:

docker-compose -f quickstart.yml exec hydra hydra token user --client-id some-id --client-secret some-secret --endpoint http://127.0.0.1:4444/ --port 5555 --scope offline

Then, I navigated to http://127.0.0.1:5555/ and clicked the “Authorize application” link (and in another test, sent a GET request to that url) and proceed as usual. The url was something like:

http://127.0.0.1:4444/oauth2/auth?audience=&client_id=authcode&max_age=0&nonce=lznqqyjivymsbkidrttnnmbr&prompt=&redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback&response_type=code&scope=openid+offline&state=cfewjwmfzmpsejqufnltqzza

I noticated that when starting my flow with some random nonce/state (that was not generated by Hydra), I would get to the last step of the flow, and then it would fail due to nonce/state mismatch.

One question about this - how and where are the nonce and state generated?
If I wish to go ahead with only server-to-server requests, would generating them in my SDK and then calling GET /oauth2/auth/ (with my generated nonce and state, as well as other required valid parameters) work?

Can you include the full “end” url? So something like http://localhost:5555/callback?....

The “end” url is something along the lines of
http://127.0.0.1:4444/oauth2/auth?audience=&client_id=some-id&consent_verifier=98160802b64c4998ba3cbef3e2b0f5a9&max_age=0&nonce=yhhiqlmoecztwuakcgfcquls&prompt=&redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback&response_type=code&scope=offline&state=frwgmvahlzwozcmvcxbqlswo

and from this url, I receive the tokens corresponding to the provided scope, in my case, access & refresh.

Maybe I misunderstood, but what I expected to receive was an authorization code, which could then be exchanged for access/refresh tokens from the /oauth2/token/ endpoint.

I followed this this example flow with a web browser as well, and found out, that the “end” url actually redirects to another url:
http://127.0.0.1:5555/callback?code=xYwh9DIAuD-C7LstD92k-iUnl6lyIeqlvYUFrneX1UE.zPDPVhdfYzBR7CnXkPmsJ9Egr5tofj70V1L_7Lh2UBM&scope=offline&state=frwgmvahlzwozcmvcxbqlswo
so it seems calling only backend requests misses the last redirect and therefore I never saw the “authorization code”. Therefore I don’t have access to the authorization code to generate new access tokens.

Is there a way to get (and retain!) the authorization code through server-to-server requests to Hydra?

Thanks again for your help.

One question about this - how and where are the nonce and state generated?

so it seems calling only backend requests misses the last redirect and therefore I never saw the “authorization code”. Therefore I don’t have access to the authorization code to generate new access tokens.

OAuth2 is a browser protocol. If you’re trying to call /oauth2/auth from a programmatic client without user interaction you’re definitely on the wrong path (highway).