Outh2 flow with spa and GraphQL server

I am new to Oauth2 and OpenID connect, I just dig into Hydra recently and find it so impressive.
My current archiecture contains spa web, GraphQL server, and serveral api services.
I have few questions about the flow.
For the entry point of login process, is it right to provide a link such as https://hydra/oauth2/auth?client_id=1234&scope=foo+bar&response_type=code&… for the spa web or from GraphQL server, such as using https://github.com/panva/node-openid-client?
Is it fine to create a login and consent app by using spa web with grapqhl server and let graphql to communicate with hydra?
If so , how could I get access token and id token from authorzation server?
Is it correct to use GraphQL server to communicate with authorization server with login and consent request and callback to spa web?
Thank in advance.

Thank you for the positive feedback!

The Admin API of ORY Hydra should not be exposed to the public internet. The Login / Consent site should therefore be server-side or use an API where they send username/password to the server which in turn then talks to Hydra.

You can do that with GraphQL if you want, just make sure that your server checks the user’s password and can not be tricked into logging in a user by an attacker.

1 Like

Thank for you reply and it sounds cool for me.
I have started to integrate all of them and I have some question about it

1.I have successfully get the authorization code when I accept from the consent page.
The callback url is something like the below.
http://127.0.0.1:3000/callback?code=O_mkGfXUpp2L2kIn_5vOdh8LDEY7QDrXmD1TUaVrh-o.f09dR0xD97PHOs-3XSLKA6EzmuPzOuIovKgsVx4BHBA&scope=openid%20offline&state=1jasofu93a3
How could I get the access token and id token ?
I check the example of token_user.go and it is execute from the backend because the client secret is reqired when asking for tokens.
Should I create a api from the app part then call oauth2/token by HTTP Basic Authorization or HTTP Body or I can call directly from the web since oauth2/token is public api?

2.After I successfully get the access token and id token, how could I secure the security of the graphql api?
I have checked the outhkeeper project, I think it only support for restful api server, is it right.
If so, I might need to check my token by using bearer token with some libraries such as https://github.com/jaredhanson/passport-http-bearer and call introspection api to make sure if the access token is still active.
Or there is any other ways thay you suggest?

3.For the logout process, hydra provides 2 ways for developers. Which one should I choose?
Is is right that OpenID Connect Front-Channel Logout is for the client which contain user interface and OpenID Connect Back-Channel Logout is for the client who doesn’t contain user interface?

4.If I want to implement OpenID Connect with silent refresh, what is the url and parameters should I set to the iframe?

I try to get the access token from my SPA but it always show the message below

Access to fetch at 'http://127.0.0.1:4444/oauth2/token/' from origin 'http://127.0.0.1:3001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

my docker configuration is below

hydra:
        image: oryd/hydra:v1.5.0
        container_name: "hydra"
        command:
            serve all --dangerous-force-http
        ports:
            - "4444:4444" # Public port
            - "4445:4445" # Admin port
        environment:
            - LOG_LEVEL=debug
            - SERVE_PUBLIC_CORS_ENABLED=true
            - SERVE_PUBLIC_CORS_ALLOWED_ORIGINS=*
            - SERVE_PUBLIC_CORS_ALLOWED_METHODS=POST,GET,PUT,PATCH,DELETE
            - SERVE_PUBLIC_CORS_ALLOWED_HEADERS=Authorization,Content-Type
            - SERVE_PUBLIC_CORS_ALLOW_CREDENTIALS=true
            - SERVE_PUBLIC_CORS_DEBUG=true
            - URLS_SELF_ISSUER=http://127.0.0.1:4444
            - URLS_CONSENT=http://127.0.0.1:3000/consent
            - URLS_LOGIN=http://127.0.0.1:3000/login
            - URLS_LOGOUT=http://127.0.0.1:3000/logout
            - DSN=postgres://postgres:password@postgres:5432/fleet-management?sslmode=disable&max_conns=20&max_idle_conns=4
            - SECRETS_SYSTEM=1234567890123456
            - OIDC_SUBJECT_IDENTIFIERS_SUPPORTED_TYPES=public,pairwise
            - OIDC_SUBJECT_IDENTIFIERS_PAIRWISE_SALT=12345678
        depends_on:
            - postgres
            - hydra-migrate

and the command when I try to create a client

docker-compose -f docker/docker-compose.yml exec hydra \
 hydra clients create --skip-tls-verify \
    --endpoint http://127.0.0.1:4445/ \
    --id spa-test-1 \
    --secret spa-secret \
    --grant-types authorization_code,refresh_token \
    --response-types token,code,id_token \
    --scope openid,offline \
    --callbacks http://127.0.0.1:3001/callback \
    --token-endpoint-auth-method none \
    --allowed-cors-origins=http://127.0.0.1:3001

the CORS setting is addd for .well-known/jwks.json but not /oauth2/token/

the log is shown below

hydra                     | [cors] 2020/05/27 08:14:23 Handler: Preflight request
hydra                     | [cors] 2020/05/27 08:14:23   Preflight response headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Headers:[Content-Type] Access-Control-Allow-Methods:[GET] Access-Control-Allow-Origin:[*] Vary:[Origin Access-Control-Request-Method Access-Control-Request-Headers]]
hydra                     | time="2020-05-27T08:14:23Z" level=info msg="started handling request" method=OPTIONS remote="172.19.0.1:36522" request=/.well-known/jwks.json
hydra                     | time="2020-05-27T08:14:23Z" level=info msg="completed handling request" measure#hydra/public: http://127.0.0.1:4444/.latency=123024 method=OPTIONS remote="172.19.0.1:36522" request=/.well-known/jwks.json status=200 text_status=OK took="123.024µs"
hydra                     | time="2020-05-27T08:14:23Z" level=info msg="started handling request" method=POST remote="172.19.0.1:36524" request=/oauth2/token/
hydra                     | time="2020-05-27T08:14:23Z" level=info msg="completed handling request" measure#hydra/public: http://127.0.0.1:4444/.latency=235129 method=POST remote="172.19.0.1:36524" request=/oauth2/token/ status=307 text_status="Temporary Redirect" took="235.129µs"
hydra                     | time="2020-05-27T08:14:23Z" level=info msg="started handling request" method=GET remote="172.19.0.1:36524" request=/.well-known/jwks.json
hydra                     | [cors] 2020/05/27 08:14:23 Handler: Actual request
hydra                     | [cors] 2020/05/27 08:14:23   Actual response added headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Origin:[*] Access-Control-Expose-Headers:[Content-Type] Vary:[Origin]]
hydra                     | time="2020-05-27T08:14:23Z" level=info msg="completed handling request" measure#hydra/public: http://127.0.0.1:4444/.latency=1352211 method=GET remote="172.19.0.1:36524" request=/.well-known/jwks.json status=200 text_status=OK took=1.352211ms

Does anyone face the same situation?

For SPA, you probably want a public client: https://www.ory.sh/hydra/docs/advanced#mobile--browser-spa-authorization

1 Like

I have started to use this way and I encounter the CORS problem. Could you help to check the situation

Or it is because the api call is not correct?

    fetch('http://127.0.0.1:4444/oauth2/token/',{
      body: JSON.stringify({
        'code': query.code,
        'grant_type': 'authorization_code',
        'client_id':'spa-test-1',
        'redirect_uri': 'http://localhost:3001/'
      }),
      headers: new Headers({
        'content-type': 'application/x-www-form-urlencoded'
      }),
      method: 'POST',
      mode: 'cors', 
      credentials: 'same-origin'
    })
  .then(function(response) {
    console.log(response);
    return response.json();
  })

You’re sending the body as JSON but the content type is application/x-www-form-urlencoded, so that’s a mismatch :slight_smile: I strongly encourage you to use an oauth2 library, there are so many good ones for node!

I tried successfully after I changed the request body
Any suggestions for the libraries? Because I only can find some library for node.js instead of browswer. Thanks