How configure grant implicit flow

Base on tutorial https://www.ory.sh/docs/guides/1-hydra/3-install/0-readme

I try to create the client with implicit grant flow:

docker run --rm -it --network hydra-network -e CLUSTER_URL=http://ory-hydra:4444 -e CLIENT_ID=admin -e CLIENT_SECRET=demo-password oryd/hydra:v0.11.6-alpine clients create --is-public --skip-tls-verify --id desktop-consumer --grant-types implicit --response-types token,code,id_token --allowed-scopes openid,offline,profile,email

Then I found that if I don’t push callbacks for the command above then my consent app can’t get consent-id from the query.

The implicit at client doesn’t listen to the callback. Then I try again with placeholder callback.

docker run --rm -it --network hydra-network -e CLUSTER_URL=http://ory-hydra:4444 -e CLIENT_ID=admin -e CLIENT_SECRET=demo-password oryd/hydra:v0.11.6-alpine clients create --is-public --skip-tls-verify --id desktop-consumer --grant-types implicit --response-types token,code,id_token --allowed-scopes openid,offline,profile,email --callbacks http://localhost/winforms.client

At win form application. After login and scope grant. I got an error in WinForm Browser:

http://localhost/winforms.client#error=invalid_grant&error_description=The+provided+authorization+grant+%2528e.g.%252C+authorization+code%252C+resource+owner+credentials%2529+or+refresh+token+is+invalid%252C+expired%252C+revoked%252C+does+not+match+the+redirection+URI+used+in+the+authorization+request%252C+or+was+issued+to+another+client&state=779e6925ca91e41e7051525644da0cdf

The win form app can found at: https://github.com/IdentityModel/IdentityModel.OidcClient.Samples/blob/master/WinFormsWebView/SampleForm.cs#L21

My configure:

var options = new OidcClientOptions
{
         Authority = "http://localhost:8080",
         ClientId = "desktop-consumer",
         Scope = "openid email profile email",
         RedirectUri = "http://localhost/winforms.client",
         Browser = new WinFormsEmbeddedBrowser()
};

Try setting LOG_LEVEL=debug and check the hydra logs, it should give a bit more information. From high level it looks ok. What confuses me though is that you’re using the code although you’re requesting the access token directly.

Please also note that the implicit flow is old and discouraged, use the authorization code flow with PKCE instead!

I have the log for both

Case 1: Register implicit with callback uri.

docker run --rm -it --network hydra-network -e CLUSTER_URL=http://ory-hydra:4444 -e CLIENT_ID=admin -e CLIENT_SECRET=demo-password oryd/hydra:v0.11.6-alpine clients create --is-public --skip-tls-verify --id desktop-consumer --grant-types implicit --response-types token,code,id_token --allowed-scopes openid,offline,profile,email --callbacks omnicasa://localhost/winforms.client

time="2018-04-21T02:35:23Z" level=info msg="Connecting with postgres://*:*@ory-hydra-postgres:5432/hydra?sslmode=disable"
time="2018-04-21T02:35:24Z" level=info msg="Connected to SQL!"
time="2018-04-21T02:35:24Z" level=info msg="Setting up telemetry - for more information please visit https://ory.gitbooks.io/hydra/content/telemetry.html"
time="2018-04-21T02:35:24Z" level=warning msg="Do not use flag --dangerous-auto-logon in production."
time="2018-04-21T02:35:24Z" level=info msg="Persisting config in file /root/.hydra.yml"
time="2018-04-21T02:35:24Z" level=info msg="Setting up http server on :4444"
time="2018-04-21T02:35:24Z" level=warning msg="HTTPS disabled. Never do this in production."
time="2018-04-21T02:39:58Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58198" request=/.well-known/openid-configuration
time="2018-04-21T02:39:58Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=815500 method=GET remote="172.18.0.1:58198" request=/.well-known/openid-configuration status=200 text_status=OK took="815.5µs"
time="2018-04-21T02:39:58Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58198" request=/.well-known/jwks.json
time="2018-04-21T02:39:58Z" level=info msg="Access denied" error=request_unauthorized reason="Token is expired, malformed or missing" request="&{rn:hydra:keys:hydra.openid.id-token:public get map[]}" scopes="[hydra.keys.get]"
time="2018-04-21T02:39:58Z" level=info msg="Access allowed" reason="The policy decision point allowed the request" request="&{rn:hydra:keys:hydra.openid.id-token:public get  map[]}" subject=
time="2018-04-21T02:39:58Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=22541900 method=GET remote="172.18.0.1:58198" request=/.well-known/jwks.json status=200 text_status=OK took=22.5419ms
time="2018-04-21T02:40:03Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58200" request="/oauth2/auth?response_type=code+id_token&nonce=cff63aa3d74c8d21cb28f03dcfd03445&state=8665585da572b534f10251b56277fa4f&code_challenge=GPAc2d4In21UttHbYHe-lteuF3YEFvv0sUVMLzWc5rA&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602"
time="2018-04-21T02:40:03Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=19313100 method=GET remote="172.18.0.1:58200" request="/oauth2/auth?response_type=code+id_token&nonce=cff63aa3d74c8d21cb28f03dcfd03445&state=8665585da572b534f10251b56277fa4f&code_challenge=GPAc2d4In21UttHbYHe-lteuF3YEFvv0sUVMLzWc5rA&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602" status=302 text_status=Found took=19.3131ms
time="2018-04-21T02:42:24Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58202" request=/.well-known/openid-configuration
time="2018-04-21T02:42:24Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=75900 method=GET remote="172.18.0.1:58202" request=/.well-known/openid-configuration status=200 text_status=OK took="75.9µs"
time="2018-04-21T02:42:24Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58202" request=/.well-known/jwks.json
time="2018-04-21T02:42:24Z" level=info msg="Access denied" error=request_unauthorized reason="Token is expired, malformed or missing" request="&{rn:hydra:keys:hydra.openid.id-token:public get map[]}" scopes="[hydra.keys.get]"
time="2018-04-21T02:42:24Z" level=info msg="Access allowed" reason="The policy decision point allowed the request" request="&{rn:hydra:keys:hydra.openid.id-token:public get  map[]}" subject=
time="2018-04-21T02:42:24Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=2937900 method=GET remote="172.18.0.1:58202" request=/.well-known/jwks.json status=200 text_status=OK took=2.9379ms
time="2018-04-21T02:42:28Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58204" request="/oauth2/auth?response_type=code+id_token&nonce=ae940fd613e8e03cf7e5bc5f143f3965&state=037813ef6c5c0ea0540aba4406e6b4b5&code_challenge=xw6TH7LjHrsQB15ngGM2-seAaJQbAWMDaxYvh_Zf-Ek&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602"
time="2018-04-21T02:42:28Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=4117800 method=GET remote="172.18.0.1:58204" request="/oauth2/auth?response_type=code+id_token&nonce=ae940fd613e8e03cf7e5bc5f143f3965&state=037813ef6c5c0ea0540aba4406e6b4b5&code_challenge=xw6TH7LjHrsQB15ngGM2-seAaJQbAWMDaxYvh_Zf-Ek&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602" status=302 text_status=Found took=4.1178ms
time="2018-04-21T02:42:28Z" level=info msg="started handling request" method=POST remote="172.18.0.1:58206" request=/oauth2/token
time="2018-04-21T02:42:28Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=94293800 method=POST remote="172.18.0.1:58206" request=/oauth2/token status=200 text_status=OK took=94.2938ms
time="2018-04-21T02:42:28Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58208" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee
time="2018-04-21T02:42:28Z" level=info msg="Access granted" client_id=consent-app request="&{[] [] { 2018-04-21 02:42:28.095775 +0000 +0000 0xc42013bb00 [hydra.consent] [hydra.consent] map[grant_type:[client_credentials] scope:[hydra.consent]] 0xc4204666f0}}" result="&{consent-app [hydra.consent] http://localhost:8080 consent-app 2018-04-21 02:42:28.095775 +0000 +0000 2018-04-21 03:42:28.1863162 +0000 UTC map[]}" subject=consent-app
time="2018-04-21T02:42:28Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=7560100 method=GET remote="172.18.0.1:58208" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee status=200 text_status=OK took=7.5601ms
time="2018-04-21T02:42:41Z" level=info msg="started handling request" method=POST remote="172.18.0.1:58210" request=/oauth2/token
time="2018-04-21T02:42:41Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=84943500 method=POST remote="172.18.0.1:58210" request=/oauth2/token status=200 text_status=OK took=84.9435ms
time="2018-04-21T02:42:41Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58212" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee
time="2018-04-21T02:42:41Z" level=info msg="Access granted" client_id=consent-app request="&{[] [] { 2018-04-21 02:42:41.194546 +0000 +0000 0xc420306100 [hydra.consent] [hydra.consent] map[grant_type:[client_credentials] scope:[hydra.consent]] 0xc420492b30}}" result="&{consent-app [hydra.consent] http://localhost:8080 consent-app 2018-04-21 02:42:41.194546 +0000 +0000 2018-04-21 03:42:41.2738752 +0000 UTC map[]}" subject=consent-app
time="2018-04-21T02:42:41Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=7413700 method=GET remote="172.18.0.1:58212" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee status=200 text_status=OK took=7.4137ms
time="2018-04-21T02:43:03Z" level=info msg="started handling request" method=POST remote="172.18.0.1:58214" request=/oauth2/token
time="2018-04-21T02:43:03Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=121296700 method=POST remote="172.18.0.1:58214" request=/oauth2/token status=200 text_status=OK took=121.2967ms
time="2018-04-21T02:43:03Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58216" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee
time="2018-04-21T02:43:03Z" level=info msg="Access granted" client_id=consent-app request="&{[] [] { 2018-04-21 02:43:03.825153 +0000 +0000 0xc420306900 [hydra.consent] [hydra.consent] map[grant_type:[client_credentials] scope:[hydra.consent]] 0xc420466bb0}}" result="&{consent-app [hydra.consent] http://localhost:8080 consent-app 2018-04-21 02:43:03.825153 +0000 +0000 2018-04-21 03:43:03.9399836 +0000 UTC map[]}" subject=consent-app
time="2018-04-21T02:43:03Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=3760900 method=GET remote="172.18.0.1:58216" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee status=200 text_status=OK took=3.7609ms
time="2018-04-21T02:43:10Z" level=info msg="started handling request" method=POST remote="172.18.0.1:58218" request=/oauth2/token
time="2018-04-21T02:43:11Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=108412600 method=POST remote="172.18.0.1:58218" request=/oauth2/token status=200 text_status=OK took=108.4126ms
time="2018-04-21T02:43:11Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58220" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee
time="2018-04-21T02:43:11Z" level=info msg="Access granted" client_id=consent-app request="&{[] [] { 2018-04-21 02:43:10.942405 +0000 +0000 0xc420306b00 [hydra.consent] [hydra.consent] map[grant_type:[client_credentials] scope:[hydra.consent]] 0xc4204675f0}}" result="&{consent-app [hydra.consent] http://localhost:8080 consent-app 2018-04-21 02:43:10.942405 +0000 +0000 2018-04-21 03:43:11.0443676 +0000 UTC map[]}" subject=consent-app
time="2018-04-21T02:43:11Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=2490700 method=GET remote="172.18.0.1:58220" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee status=200 text_status=OK took=2.4907ms
time="2018-04-21T02:43:11Z" level=info msg="started handling request" method=PATCH remote="172.18.0.1:58222" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee/accept
time="2018-04-21T02:43:11Z" level=info msg="Access granted" client_id=consent-app request="&{[] [] { 2018-04-21 02:43:10.942405 +0000 +0000 0xc420306d00 [hydra.consent] [hydra.consent] map[grant_type:[client_credentials] scope:[hydra.consent]] 0xc42016a000}}" result="&{consent-app [hydra.consent] http://localhost:8080 consent-app 2018-04-21 02:43:10.942405 +0000 +0000 2018-04-21 03:43:11.0443676 +0000 UTC map[]}" subject=consent-app
time="2018-04-21T02:43:11Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=6739800 method=PATCH remote="172.18.0.1:58222" request=/oauth2/consent/requests/eff35b03-ac23-437a-a446-40fb678666ee/accept status=204 text_status="No Content" took=6.7398ms
time="2018-04-21T02:43:11Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58204" request="/oauth2/auth?response_type=code+id_token&nonce=ae940fd613e8e03cf7e5bc5f143f3965&state=037813ef6c5c0ea0540aba4406e6b4b5&code_challenge=xw6TH7LjHrsQB15ngGM2-seAaJQbAWMDaxYvh_Zf-Ek&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602&consent=eff35b03-ac23-437a-a446-40fb678666ee&consent_csrf=108e476d-4343-4c91-bbc5-65ff817ef477"
time="2018-04-21T02:43:11Z" level=error msg="An error occurred" debug="The client is not allowed to use the authorization_code grant type" error=invalid_grant
time="2018-04-21T02:43:11Z" level=debug msg="Stack trace: \ngithub.com/ory/hydra/vendor/github.com/ory/fosite/handler/openid.(*OpenIDConnectHybridHandler).HandleAuthorizeEndpointRequest\n\t/go/src/github.com/ory/hydra/vendor/github.com/ory/fosite/handler/openid/flow_hybrid.go:70\ngithub.com/ory/hydra/vendor/github.com/ory/fosite.(*Fosite).NewAuthorizeResponse\n\t/go/src/github.com/ory/hydra/vendor/github.com/ory/fosite/authorize_response_writer.go:35\ngithub.com/ory/hydra/oauth2.(*Handler).AuthHandler\n\t/go/src/github.com/ory/hydra/oauth2/handler.go:453\ngithub.com/ory/hydra/oauth2.(*Handler).AuthHandler-fm\n\t/go/src/github.com/ory/hydra/oauth2/handler.go:119\ngithub.com/ory/hydra/vendor/github.com/julienschmidt/httprouter.(*Router).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/julienschmidt/httprouter/router.go:299\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.Wrap.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:41\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:24\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(middleware).ServeHTTP-fm\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\ngithub.com/ory/hydra/cmd/server.(*Handler).rejectInsecureRequests\n\t/go/src/github.com/ory/hydra/cmd/server/handler.go:200\ngithub.com/ory/hydra/cmd/server.(*Handler).(github.com/ory/hydra/cmd/server.rejectInsecureRequests)-fm\n\t/go/src/github.com/ory/hydra/cmd/server/handler.go:113\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:24\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(middleware).ServeHTTP-fm\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/meatballhat/negroni-logrus.(*Middleware).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/meatballhat/negroni-logrus/middleware.go:136\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(*Negroni).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:73\ngithub.com/ory/hydra/vendor/github.com/rs/cors.(*Cors).Handler.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/rs/cors/cors.go:200\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\ngithub.com/ory/hydra/vendor/github.com/gorilla/context.ClearHandler.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/gorilla/context/context.go:141\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\nnet/http.serverHandler.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2619\nnet/http.(*conn).serve\n\t/usr/local/go/src/net/http/server.go:1801\nruntime.goexit\n\t/usr/local/go/src/runtime/asm_amd64.s:2337"
time="2018-04-21T02:43:11Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=9097200 method=GET remote="172.18.0.1:58204" request="/oauth2/auth?response_type=code+id_token&nonce=ae940fd613e8e03cf7e5bc5f143f3965&state=037813ef6c5c0ea0540aba4406e6b4b5&code_challenge=xw6TH7LjHrsQB15ngGM2-seAaJQbAWMDaxYvh_Zf-Ek&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602&consent=eff35b03-ac23-437a-a446-40fb678666ee&consent_csrf=108e476d-4343-4c91-bbc5-65ff817ef477" status=302 text_status=Found took=9.0972ms

Case 2: I register again without callback:

docker run --rm -it --network hydra-network -e CLUSTER_URL=http://ory-hydra:4444 -e CLIENT_ID=admin -e CLIENT_SECRET=demo-password oryd/hydra:v0.11.6-alpine clients create --is-public --skip-tls-verify --id desktop-consumer --grant-types implicit --response-types token,code,id_token --allowed-scopes openid,offline,profile,email

time="2018-04-21T02:52:29Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=6077600 method=GET remote="172.18.0.1:58232" request=/.well-known/jwks.json status=200 text_status=OK took=6.0776ms
time="2018-04-21T02:52:32Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58234" request="/oauth2/auth?response_type=code+id_token&nonce=f4a8f2a948f918be37301b2a8ff75f69&state=4f0c2bcd727b08308d1538681a5b3b78&code_challenge=DQ2zD1Li_GseiSVa5fjqZHEmVKaYx4DKDdBNLFzTsoE&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602"
time="2018-04-21T02:52:32Z" level=error msg="An error occurred" debug=invalid_request error=invalid_request hint="Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified."
time="2018-04-21T02:52:32Z" level=debug msg="Stack trace: \ngithub.com/ory/hydra/vendor/github.com/ory/fosite.(*Fosite).NewAuthorizeRequest\n\t/go/src/github.com/ory/hydra/vendor/github.com/ory/fosite/authorize_request_handler.go:55\ngithub.com/ory/hydra/oauth2.(*Handler).AuthHandler\n\t/go/src/github.com/ory/hydra/oauth2/handler.go:411\ngithub.com/ory/hydra/oauth2.(*Handler).AuthHandler-fm\n\t/go/src/github.com/ory/hydra/oauth2/handler.go:119\ngithub.com/ory/hydra/vendor/github.com/julienschmidt/httprouter.(*Router).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/julienschmidt/httprouter/router.go:299\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.Wrap.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:41\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:24\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(middleware).ServeHTTP-fm\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\ngithub.com/ory/hydra/cmd/server.(*Handler).rejectInsecureRequests\n\t/go/src/github.com/ory/hydra/cmd/server/handler.go:200\ngithub.com/ory/hydra/cmd/server.(*Handler).(github.com/ory/hydra/cmd/server.rejectInsecureRequests)-fm\n\t/go/src/github.com/ory/hydra/cmd/server/handler.go:113\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:24\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(middleware).ServeHTTP-fm\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/meatballhat/negroni-logrus.(*Middleware).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/meatballhat/negroni-logrus/middleware.go:136\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(*Negroni).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:73\ngithub.com/ory/hydra/vendor/github.com/rs/cors.(*Cors).Handler.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/rs/cors/cors.go:200\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\ngithub.com/ory/hydra/vendor/github.com/gorilla/context.ClearHandler.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/gorilla/context/context.go:141\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\nnet/http.serverHandler.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2619\nnet/http.(*conn).serve\n\t/usr/local/go/src/net/http/server.go:1801\nruntime.goexit\n\t/usr/local/go/src/runtime/asm_amd64.s:2337"
time="2018-04-21T02:52:32Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=747500 method=GET remote="172.18.0.1:58234" request="/oauth2/auth?response_type=code+id_token&nonce=f4a8f2a948f918be37301b2a8ff75f69&state=4f0c2bcd727b08308d1538681a5b3b78&code_challenge=DQ2zD1Li_GseiSVa5fjqZHEmVKaYx4DKDdBNLFzTsoE&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602" status=302 text_status=Found took="747.5µs"
time="2018-04-21T02:52:32Z" level=info msg="started handling request" method=POST remote="172.18.0.1:58236" request=/oauth2/token
time="2018-04-21T02:52:32Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=97272000 method=POST remote="172.18.0.1:58236" request=/oauth2/token status=200 text_status=OK took=97.272ms
time="2018-04-21T02:52:54Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58232" request=/.well-known/openid-configuration
time="2018-04-21T02:52:54Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=38300 method=GET remote="172.18.0.1:58232" request=/.well-known/openid-configuration status=200 text_status=OK took="38.3µs"
time="2018-04-21T02:52:54Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58232" request=/.well-known/jwks.json
time="2018-04-21T02:52:54Z" level=info msg="Access denied" error=request_unauthorized reason="Token is expired, malformed or missing" request="&{rn:hydra:keys:hydra.openid.id-token:public get map[]}" scopes="[hydra.keys.get]"
time="2018-04-21T02:52:54Z" level=info msg="Access allowed" reason="The policy decision point allowed the request" request="&{rn:hydra:keys:hydra.openid.id-token:public get  map[]}" subject=
time="2018-04-21T02:52:54Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=2453300 method=GET remote="172.18.0.1:58232" request=/.well-known/jwks.json status=200 text_status=OK took=2.4533ms
time="2018-04-21T02:52:57Z" level=info msg="started handling request" method=GET remote="172.18.0.1:58234" request="/oauth2/auth?response_type=code+id_token&nonce=1f95527129faad193d885b2b130dbb72&state=cf7353743a39555ca503b783a888220b&code_challenge=2zNt9Jbm5ejwwcbc7lzdKMVszbSSI--DqkRDc9yn8AA&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602"
time="2018-04-21T02:52:57Z" level=error msg="An error occurred" debug=invalid_request error=invalid_request hint="Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified."
time="2018-04-21T02:52:57Z" level=debug msg="Stack trace: \ngithub.com/ory/hydra/vendor/github.com/ory/fosite.(*Fosite).NewAuthorizeRequest\n\t/go/src/github.com/ory/hydra/vendor/github.com/ory/fosite/authorize_request_handler.go:55\ngithub.com/ory/hydra/oauth2.(*Handler).AuthHandler\n\t/go/src/github.com/ory/hydra/oauth2/handler.go:411\ngithub.com/ory/hydra/oauth2.(*Handler).AuthHandler-fm\n\t/go/src/github.com/ory/hydra/oauth2/handler.go:119\ngithub.com/ory/hydra/vendor/github.com/julienschmidt/httprouter.(*Router).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/julienschmidt/httprouter/router.go:299\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.Wrap.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:41\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:24\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(middleware).ServeHTTP-fm\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\ngithub.com/ory/hydra/cmd/server.(*Handler).rejectInsecureRequests\n\t/go/src/github.com/ory/hydra/cmd/server/handler.go:200\ngithub.com/ory/hydra/cmd/server.(*Handler).(github.com/ory/hydra/cmd/server.rejectInsecureRequests)-fm\n\t/go/src/github.com/ory/hydra/cmd/server/handler.go:113\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:24\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(middleware).ServeHTTP-fm\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/meatballhat/negroni-logrus.(*Middleware).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/meatballhat/negroni-logrus/middleware.go:136\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.middleware.ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:33\ngithub.com/ory/hydra/vendor/github.com/urfave/negroni.(*Negroni).ServeHTTP\n\t/go/src/github.com/ory/hydra/vendor/github.com/urfave/negroni/negroni.go:73\ngithub.com/ory/hydra/vendor/github.com/rs/cors.(*Cors).Handler.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/rs/cors/cors.go:200\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\ngithub.com/ory/hydra/vendor/github.com/gorilla/context.ClearHandler.func1\n\t/go/src/github.com/ory/hydra/vendor/github.com/gorilla/context/context.go:141\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:1918\nnet/http.serverHandler.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2619\nnet/http.(*conn).serve\n\t/usr/local/go/src/net/http/server.go:1801\nruntime.goexit\n\t/usr/local/go/src/runtime/asm_amd64.s:2337"
time="2018-04-21T02:52:57Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=1288600 method=GET remote="172.18.0.1:58234" request="/oauth2/auth?response_type=code+id_token&nonce=1f95527129faad193d885b2b130dbb72&state=cf7353743a39555ca503b783a888220b&code_challenge=2zNt9Jbm5ejwwcbc7lzdKMVszbSSI--DqkRDc9yn8AA&code_challenge_method=S256&client_id=desktop-consumer&scope=openid+email+profile+email&redirect_uri=omnicasa%3A%2F%2Flocalhost%2Fwinforms.client&response_mode=form_post&customer-id=602" status=302 text_status=Found took=1.2886ms
time="2018-04-21T02:54:03Z" level=info msg="started handling request" method=POST remote="172.18.0.1:58238" request=/oauth2/token
time="2018-04-21T02:54:03Z" level=info msg="completed handling request" measure#http://localhost:8080.latency=99288300 method=POST remote="172.18.0.1:58238" request=/oauth2/token status=200 text_status=OK took=99.2883ms

I still don’t understand that if I use Authorization Code Grant mean at native app must listen callback base on loopback url like: http://localhost:12345.
The port must register with callback but I want random port to avoid conflict exiting port so how to resolve this case?

Ok, so it says in the logs:

time=“2018-04-21T02:43:11Z” level=error msg=“An error occurred” debug=“The client is not allowed to use the authorization_code grant type” error=invalid_grant

Your client is allowed to use the implicit flow, but the hybrid flow (requesting a token) needs the authorization_code grant type which you haven’t whitelisted in your client.

The second request fails because you did not specify a redirect/callback url

time=“2018-04-21T02:52:57Z” level=error msg=“An error occurred” debug=invalid_request error=invalid_request hint=“Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified.”

So how specificity redirect/callback url with dynamic port for consumer? Does ORY Hidra support callback URL pattern?

That’s not possible, not secure, and not allowed per standard spec. You must use a well-known and fixed port as callback URL, otherwise it’s insecure.

Not sure what you mean, but you’re using the callback URL, so yes?

Actually, I try with this client tool and it work with Identity Server 4. On C# app run on Windows/Linux as .NET Core can’t handler schema callback url style so only user loopback url with random port only.

Sorry, I can’t help with specific OAuth2 or OpenID Connect implementations. My recommendation is to not use the implicit flow at all and instead use the Authorize Code Flow with PKCE.

1 Like

By the way, I did not invent that statements, it’s on the official oauth website: https://oauth.net/2/grant-types/implicit/

The Implicit grant type is a simplified flow that can be used by public clients, where the access token is returned immediately without an extra authorization code exchange step.

It is generally not recommended to use the implicit flow (and some servers prohibit this flow entirely). In the time since the spec was originally written, the industry best practice has changed to recommend that public clients should use either the authorization code flow without the client secret, or use the PKCE extension instead.

More information can be found on the OAuth mailing list from: Redhat, Deutsche Telekom, and Smart Health IT.

More resources

1 Like

Is it possible to have Authorize Code Flow with PKCE in hydra? It seems like development is going on. If there is any way to to include PKCE in hydra authorize code flow then please let me know.

PKCE is fully supported

Thanks for your reply. Can you please give any reference/doc how to use it in hydra Authorize Code flow with PKCE?
I found in https://www.ory.sh/docs/hydra/advanced link that PKCE can be enable by following way

--token-endpoint-auth-method none

So I created a client in following way

docker run --rm -it \
  -e HYDRA_ADMIN_URL=https://192.168.0.4:4445 \
  --network hydraguide \
  oryd/hydra:v1.0.0-rc.3_oryOS.9 \
  clients create --skip-tls-verify \ --token-endpoint-auth-method none \
    --id testPKCE \
    --grant-types authorization_code,refresh_token \
    --response-types token,code,id_token \
    --scope email,phone \
    --callbacks https://mysite.com:3000/callback

Then I send code_challenge along with other config as describe in https://www.oauth.com/oauth2-servers/pkce/

authConfig = {
    redirect_uri: 'https://mysite.com:3000/callback',
    scope: 'openid',
    state: 'clondxkirhddzajqkmfpgsdwlnoncepppuimiwnrfjpdidjgesgkryn',
    code_challenge: "clondxkirhddzajqkmfpgsdwlnoncepppuimiwnrf"
}

Then when I receive the authorization code in callback I am using the key to get the access token

code_verifier: "clondxkirhddzajqkmfpgsdwlnoncepppuimiwnrf"

But the issue is if I send the wrong key/code in code_verifier it still giving me the access token. So it seems like it’s not considering code_verifier.

May be I miss understood how PKCE flow works. Please advice.

It’s not possible for me to tell what’s going wrong without seeing the actual URLs or with a reproducible step by step guide. PKCE should work properly and has several tests that make sure that, if used correctly, it shouldn’t be possible to bypass PKCE.

Sorry for bother you again. Is there any documentation to use PKCE in hydra? I know I am doing some mistakes :).

I am not allowed to give more then 3 reply as a new user. So editing this reply. I hope you will see it.

  1. Setup the Hydra server in a docker
docker run -d \
  --name hydra \
  --network hydraguide \
  -p 4444:4444 \
  -p 4445:4445 \
  -e OAUTH2_CONSENT_URL=https://mysite.com:3000/consent \
    -e OAUTH2_LOGIN_URL=https://mysite.com:3000/login \
    -e OAUTH2_ISSUER_URL=https://mysite.com:1444 \
    -e SYSTEM_SECRET=$SYSTEM_SECRET \
    -e DATABASE_URL=$DATABASE_URL \
    -e HTTPS_ALLOW_TERMINATION_FROM=172.18.0.1/20,192.168.0.1/16 \
  oryd/hydra:v1.0.0-rc.3_oryOS.9 serve all

I also setup API Getaways which I am not giving the detail here.

  1. Created a test client without PKCE
docker run --rm -it \
  -e HYDRA_ADMIN_URL=https://192.168.0.4:1445 \
  --network hydraguide \
  oryd/hydra:v1.0.0-rc.3_oryOS.9 \
  clients create --skip-tls-verify \
    --id another-consumer \
    --secret consumer-secret \
    --grant-types authorization_code,refresh_token,client_credentials,implicit \
    --response-types token,code,id_token \
    --scope openid,offline \
    --callbacks https://mysite.com/callback
  1. downloaded the user and consent app from https://github.com/ory/hydra-login-consent-node and ran it
  2. Created a node application as a client. Everything worked as expected. Authorize URL generated >> Login page came up >> Authorize Page came up >> Got the Access token
  3. Now I tried to create a client with PKCE (Note: I didn’t provide the client secret but after client creation it generated the client secret)
docker run --rm -it \
  -e HYDRA_ADMIN_URL=https://192.168.0.4:4445 \
  --network hydraguide \
  oryd/hydra:v1.0.0-rc.3_oryOS.9 \
  clients create --skip-tls-verify \ --token-endpoint-auth-method none \
    --id testPKCE \
    --grant-types authorization_code,refresh_token \
    --response-types token,code,id_token \
    --scope email,phone \
    --callbacks https://mysite.com:3000/callback
  1. In my client app I added code_challenge in the auth config in the first call to Hydra server and code_verifier when requesting access token. Everything works fine I get the access token successfully. Here is the code.
const express = require('express')
const router = express.Router()
const OAuth2 = require('simple-oauth2')
const qs = require('querystring')
const _scope = ['openid', 'offline']
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
const redirectUri = 'https://mysite.com/callback'

const oauth2 = OAuth2.create({
    client: {
        // todo: change hard coding 
        // id: qs.escape('another-consumer'), // process.env.HYDRA_CLIENT_ID),
        // secret: qs.escape('consumer-secret') //process.env.HYDRA_CLIENT_SECRET)
        id: qs.escape('testPKCE'),
        secret: qs.escape('L88eQA2Gf36HTji_AWg3jg0w4b')
    },
    auth: {
        tokenHost: endpoint = 'https://mysite.com:1444/', //9000 //process.env.HYDRA_URL,
        authorizePath: authorizePath = '/oauth2/auth',
        tokenPath: tokenPath = '/oauth2/token'
    },
    // These are important for simple-oauth2 to work properly.
    options: {
        useBodyAuth: false,
        useBasicAuthorizationHeader: true
    }
});
const authConfig = {
    redirect_uri: redirectUri,
    scope: _scope.join(' '), //: 'openid',
    state: 'clondxkirhddzajqkmfpgsdwlnoncepppuimiwnrfjpdidjgesgkryn',
    code_challenge: "clondxkirhddzajqkmfpgsdwlnoncepppuimiwnrf"
}
console.log('auth config:', authConfig)
const authorizationUrl = oauth2.authorizationCode.authorizeURL(authConfig);
console.log('auth url', authorizationUrl);
/* GET home page. */
router.get('/', (req, res, next) => {
    res.render('index', { title: 'Express', authUrl: authorizationUrl });
});

// Callback service parsing the authorization token and asking for the access token
router.get('/callback', async(req, res) => {
    // console.log(req)
    const code = req.query.code;
    const options = {
        code,
        redirect_uri: redirectUri,
        code_verifier: "clondxkirhddzajqkmfpgsdwlnoncepppuimiwnrf",
        _scope //: 'openid'
    };
    console.log('callback code:', options);
    try {
        //refreshToken();
        const result = await oauth2.authorizationCode.getToken(options)

        console.log('The resulting token: ', result);

        const token = oauth2.accessToken.create(result);

        res.setHeader('Content-Type', 'application/json');
        res.send(JSON.stringify(token));
        // return res.status(200).json(token)
    } catch (error) {
        console.error('Access Token Error', error);
        return res.status(500).json('Authentication failed');
    }
});


module.exports = router;
  1. Now I tried to fail the access token so I provide a wrong code_verifier but still getting the access token.

When I am sending the wrong key in code_verifier hydra should not provide access token right?

Show me what you’re doing and I can tell you what you’re doing wrong, but I’m not going to explain PKCE completely here :wink: