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

Implement Hydra integration #273

Closed
sczj opened this issue Mar 3, 2020 · 65 comments
Closed

Implement Hydra integration #273

sczj opened this issue Mar 3, 2020 · 65 comments
Assignees
Labels
feat New feature or request.
Milestone

Comments

@sczj
Copy link

sczj commented Mar 3, 2020

Configure Hydra's authorization authentication, how it should be configured in the profile

@aeneasr
Copy link
Member

aeneasr commented Mar 3, 2020

This will be possible in the future but we will first have to implement some basic features here.

@aeneasr aeneasr added the feat New feature or request. label Mar 3, 2020
@aeneasr aeneasr added this to the v0.3.0-alpha.1 milestone Mar 3, 2020
@aeneasr aeneasr changed the title Configure Hydra's authorization authentication Implement Hydra integration Mar 3, 2020
@raffis
Copy link

raffis commented Mar 5, 2020

This will be possible in the future but we will first have to implement some basic features here.

Do you have any vague idea when that will be the case? For me personally kratos makes only sense as being the authentication/identity provider for hydra.

@aeneasr
Copy link
Member

aeneasr commented Mar 5, 2020

I mean you can simply do this yourself today. Just add the Hydra snippet to your Kratos Self-Service Login UI and add a consent page.

@raffis
Copy link

raffis commented Mar 5, 2020

Yes that is what I did for now. But would be awesome to have this out of the box.

@aeneasr
Copy link
Member

aeneasr commented Mar 5, 2020

The flow will somewhat be similar anyways, maybe with a small integration for login so if you solved that already today you're good to go with this for the next half year at least.

Regarding timelines, we do not give any unless t < 7d. Most issues have milestones attached (like this one) and you can check the overall milestones in the milestone tab which gives you a vague idea of how the feature is prioritized.

@hudongcheng
Copy link

hudongcheng commented Mar 19, 2020

@aeneasr @raffis Excuse me for asking, is there a sample code that integrate with Hydra?

@aeneasr
Copy link
Member

aeneasr commented Mar 19, 2020

Not yet, we're still working on some other features. Maybe you can ask in the community or on the forum if someone has already done it and can help you.

@tacurran
Copy link
Member

@hudongcheng please see the comment here #273 from @raffis regarding a sample app "Yes that is what I did for now."

@romcok
Copy link

romcok commented Jun 16, 2020

Yes that is what I did for now. But would be awesome to have this out of the box.

Hi, please does anyone have a hydra snippet for its integration into Kratos? It's super hard to do when there's no demonstration.

@exfly
Copy link

exfly commented Jun 20, 2020

+1

@jpbogle
Copy link

jpbogle commented Jun 20, 2020

I actually happened to have tried to do this as well.

I have forked the kratos example UI and integrated the hydra snippet into it and was planning to keep working on that so you could take a took and follow along here if you want

jpbogle/kratos-selfservice-ui-node@edd2a47
https://github.com/jpbogle/kratos-selfservice-ui-node

The outstanding issue I am looking at is keeping the Hydra challenge throughout a login or registration flow with kratos without using cookies. I have discussed this briefly here on the Ory forums

https://community.ory.sh/t/ory-hydra-with-ory-kratos-as-idp/1845

@aeneasr
Copy link
Member

aeneasr commented Jul 27, 2020

For anyone looking, I've pushed this back because there's a way to solve this in the selfservice app. You can find the code here: https://github.com/ory/kratos-selfservice-ui-node/tree/hydra-integration/contrib/hydra

Please be aware that there are possible security issues if you do not implement it the way it is done there. To make this easier in the future, we'll add the implementation to ORY Kratos directly. But I'm pushing this back because there is a way to solve it now!

@aeneasr aeneasr added the corp/m2 Up for M2 at Ory Corp. label Aug 19, 2020
@aeneasr aeneasr added blocking Blocks milestones or other issues or pulls. corp/m3 Up for M3 at Ory Corp. and removed corp/m2 Up for M2 at Ory Corp. labels Oct 7, 2020
@CSRaghunandan
Copy link

@aeneasr Thanks a lot for the work you've put for the new 0.5.0 release.
I was thinking, what changes would need to be made to get this to work: https://github.com/ory/kratos-selfservice-ui-node/tree/hydra-integration/contrib/hydra . This works on the older version of Kratos.

We were exploring Kratos as a userDB for Hydra and wanted to explore this branch further, but there were a few issues which we were waiting to be fixed in 0.5.0.

@aeneasr
Copy link
Member

aeneasr commented Oct 16, 2020

Good question! I haven't looked at the code but I think what you would need to do is just update the SDK usages to bring them up to the 0.5 release. As said earlier, we're still planning a seamless integration between the two projects but the refactor of the 0.5 release was a lot of work which is why we weren't able to do it for now.

@CSRaghunandan
Copy link

Good question! I haven't looked at the code but I think what you would need to do is just update the SDK usages to bring them up to the 0.5 release. As said earlier, we're still planning a seamless integration between the two projects but the refactor of the 0.5 release was a lot of work which is why we weren't able to do it for now.

I see. Thanks for the reply.

@aeneasr
Copy link
Member

aeneasr commented Jun 20, 2022

Hi, yes, we’re working actively on it

@vinckr
Copy link
Member

vinckr commented Jun 20, 2022

Hey @DzianisH
In the meantime check out this community integration: https://github.com/atreya2011/go-kratos-test/tree/hydra-consent

@openscript
Copy link

I'm happy to see the issue is marked as completed. Is it now possible to access the identities inside a Kratos instance via Hydras OIDC?

@mvrahden
Copy link

Amazing 🎉

@aeneasr
Copy link
Member

aeneasr commented Oct 26, 2022

Yes exactly, we will add a quick guide to get this working in an example to the release notes. We want to release it today, but are still working on getting this to production before doing so.

@aeneasr
Copy link
Member

aeneasr commented Oct 26, 2022

Thank you all for your patience! I know it's been a long time coming :)

@bbroniewski
Copy link

bbroniewski commented Nov 4, 2022

Is that guide uploaded somewhere already? I can not find it. Thank you in advance!
@aeneasr

@dezeroku
Copy link

dezeroku commented Nov 7, 2022

@bbroniewski it works for me (meaning I can obtain tokens from hydra, based on Kratos' user data/login process) with the following config:

  1. kratos docker image built from master, oauth2_provider.url in config set to hydra's admin API
  2. consent v2.0.1, pointing to Hydra's admin/public API as usual
  3. kratos' selfservice UI image :latest, pointing to kratos admin/public API as usual
  4. hydra v2.0.1 with urls.consent pointing to consent API as usual and login/logout URLs pointing to Kratos' selfservice UI

@bbroniewski
Copy link

Hi @dezeroku, thank you for your help. I will wait for some time for official guide, if nothing will be available then for sure I will give it a try according to your points. Thank you again.

@aeneasr
Copy link
Member

aeneasr commented Nov 8, 2022

If you want to check out the flow on the Ory Network (where the feature flag and release is available), check out: https://www.ory.sh/run-oauth2-server-open-source-api-security/

:)

To do it yourself, the guide from @dezeroku is on point

@dezeroku
Copy link

dezeroku commented Nov 8, 2022

@aeneasr on a side note, do you plan a tagged release with this change anytime soon or there's something else that you'd like to merge first?

@sidharthramesh
Copy link

Wow! This is great! Any idea when there'll be a release @aeneasr?

@sidharthramesh
Copy link

  1. hydra v2.0.1 with urls.consent pointing to consent API as usual and login/logout URLs pointing to Kratos' selfservice UI

@dezeroku, what did you use as the logout URL in the hydra config? The Kratos self-service UI doesn't have a specific logout endpoint and generates the logout link dynamically. My hydra.yml looks like this:

serve:
  cookies:
    same_site_mode: Lax

urls:
  self:
    issuer: http://127.0.0.1:4444
  consent: http://127.0.0.1:3000/consent
  login: http://127.0.0.1:4455/login
  logout: http://127.0.0.1:4455/logout # will not work??

secrets:
  system:
    - youReallyNeedToChangeThis

oidc:
  subject_identifiers:
    supported_types:
      - pairwise
      - public
    pairwise:
      salt: youReallyNeedToChangeThis

@dezeroku
Copy link

@sidharthramesh I am afraid you're right, I've used the selfservice's /logout (nonexistent) endpoint in hydra configuration and never really got around to testing it. At this state of testing I was mostly using Kratos' logout option on selfservice's welcome page and cleaning cookies from time to time.

I think a good starting point would be to use the /logout endpoint from the consent app? And if you get into a weird login redirection loop in which:

  1. You log out of Hydra
  2. Get redirected to Kratos' selfservice login page
  3. Get redirected to Hydra with cookie that Kratos remembered from last login
  4. Get token from Hydra again with the same user that was logged out

you might consider modifying the logic in https://github.com/ory/hydra-login-consent-node/blob/master/src/routes/logout.ts#L63 to also redirect to Kratos' logout URL defined as in selfservice: https://github.com/ory/kratos-selfservice-ui-node/blob/master/src/routes/welcome.ts#L22 Not sure if this would be needed at all or Hydra would handle both Hydra and Kratos "sessions" logout behind the scenes.

@bbroniewski
Copy link

This is where official versions and guide is required, of course we may all together try to solve those issues, and reverse ingeener all of those, even looking at the code but those problems were already solved. @aeneasr could you tell us about plans? Is there a plan to publish it (versions and guide) or there was some decision change to not publish it to open community right now?

@genedy2017
Copy link

I've been able to integrate kratos as IDP provider for hydra and it works beautifully after kratos 0.11.0 release. Thanks so much for the great work you do guys!

One issue I encountered while implementing is that the oauth2_provider.url is being used when communicating with both hydra public and admin endpoints. In our production setup, hydra admin endpoints are not accessible publicly and are served through a different url than the public endpoints.

Thus when kratos tried to access hydra admin endpoint (to get login_challenge details) using the public url configured in oauth2_provider.url, it reported a 404 error. I was able to fix that using an nginx rewrite rule for now, but it would be nice to have a separate config maybe oauth2_provider.admin_url or so.

@vinckr
Copy link
Member

vinckr commented Dec 15, 2022

Hey,
that is good to hear @genedy2017 ! If you ever want to do a writeup of your setup for other community members, feel free to reach out to me :)

As for your issue, I think it would be best if you open a new discussion (or even a bug report?) for it. Some crazies like me follow all the threads, but maintainers mainly look at new issues or discussions.

@genedy2017
Copy link

Hey @vinckr,

If you ever want to do a writeup of your setup for other community members, feel free to reach out to me :)

Would love to! I'll prepare an article and reach out to you within a few weeks.

I'll open a new issue as per your recommendation.

@LasseRosenow
Copy link

@bbroniewski it works for me (meaning I can obtain tokens from hydra, based on Kratos' user data/login process) with the following config:

1. kratos docker image built from master, oauth2_provider.url in config set to hydra's admin API

2. consent v2.0.1, pointing to Hydra's admin/public API as usual

3. kratos' selfservice UI image :latest, pointing to kratos admin/public API as usual

4. hydra v2.0.1 with urls.consent pointing to consent API as usual and login/logout URLs pointing to Kratos' selfservice UI

What confuses me about "2.", that why do I need the hydra "consent" user-interface if I use the kratos ui for login and logout?

@dezeroku
Copy link

dezeroku commented Jan 8, 2023

@LasseRosenow If I remember correctly, kratos ui didn't have "consent" screen implemented at the time (maybe it's changed now, I don't know). So for the "full OAuth experience" you needed both login screen (kratos UI) and consent screen (consent service)

@muwiess
Copy link

muwiess commented Jan 31, 2023

Hey @vinckr,

If you ever want to do a writeup of your setup for other community members, feel free to reach out to me :)

Would love to! I'll prepare an article and reach out to you within a few weeks.

I'll open a new issue as per your recommendation.

I'm new to install Kratos and Hydra implementation, wondering if there's a guide that anyone can share?

@vinckr
Copy link
Member

vinckr commented Feb 1, 2023

Hello @muwiess
Check out this discussion for the "status quo":
#2976 (comment)

There is no "out-of-the-box" guide yet, but there are a lot of examples around. If you would like to contribute a guide for the self-hosted integration of Kratos/Hydra, I would be happy to help you!
Otherwise you can test out the integration without any previous for on the managed Ory Network

@jmls
Copy link

jmls commented Mar 7, 2023

@muwiess were you able to get this working ? If so, do you have any docs we can steal ? :)

@ellicodan
Copy link

@bbroniewski it works for me (meaning I can obtain tokens from hydra, based on Kratos' user data/login process) with the following config:

  1. kratos docker image built from master, oauth2_provider.url in config set to hydra's admin API
  2. consent v2.0.1, pointing to Hydra's admin/public API as usual
  3. kratos' selfservice UI image :latest, pointing to kratos admin/public API as usual
  4. hydra v2.0.1 with urls.consent pointing to consent API as usual and login/logout URLs pointing to Kratos' selfservice UI

@dezeroku I'm struggling to get this to work. I have tried integrating Hydra/Kratos login flow using hydra-login-consent-node + kratos-selfservice-ui-node, and also my custom UI.

docker compose file:

name: ory

networks:
  postgres:
    external: true
    name: postgres_internal
  public:
    external: true
    name: public
  mailhog:
    external: true
    name: mailhog_internal

volumes:
  kratos:
    name: kratos_data

x-kratos-volumes: &kratos-volumes
  volumes:
    - ${DEV_CONFIG_DIR}/kratos:/etc/config/kratos
    - kratos:/var/lib/sqlite
    - kratos:/home/ory

services:
  kratos-migrate:
    # image: oryd/kratos:${KRATOS_VERSION}
    image: ellicodan/kratos:latest
    container_name: ${KRATOS_HOST_NAME}-migrate
    <<: *kratos-volumes
    command: --config /etc/config/kratos/kratos.yml migrate sql --read-from-env --yes
    environment:
      - DSN=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST_NAME}:${POSTGRES_PORT}/${KRATOS_DB_NAME}?sslmode=disable&max_conns=20&max_idle_conns=4 
      - LOG_LEVEL=info
    networks:
      - postgres

  hydra-migrate:
    image: oryd/hydra:$HYDRA_VERSION
    container_name: ${HYDRA_HOST_NAME}-migrate
    command: migrate sql --read-from-env --yes
    environment:
      - DSN=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST_NAME}:${POSTGRES_PORT}/${HYDRA_DB_NAME}?sslmode=disable&max_conns=20&max_idle_conns=4 
    networks:
      - postgres

  kratos:
    # image: oryd/kratos:${KRATOS_VERSION}
    image: ellicodan/kratos:latest
    container_name: ${KRATOS_HOST_NAME}
    <<: *kratos-volumes
    command: serve --config /etc/config/kratos/kratos.yml --watch-courier --dev
    environment:
      - DSN=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST_NAME}:${POSTGRES_PORT}/${KRATOS_DB_NAME}?sslmode=disable&max_conns=20&max_idle_conns=4  # Postgresql
      - LOG_LEVEL=info
    networks:
      - public
      - postgres
      - mailhog
    ports:
      - 4433:4433 # public
      - 4434:4434 # admin
    depends_on:
      kratos-migrate:
        condition: service_completed_successfully

  hydra:
    image: oryd/hydra:$HYDRA_VERSION
    container_name: $HYDRA_HOST_NAME
    volumes:
      - ${DEV_CONFIG_DIR}/hydra:/etc/config/hydra
    command: serve all --config /etc/config/hydra/hydra.yml --dev
    environment:
      - DSN=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST_NAME}:${POSTGRES_PORT}/${HYDRA_DB_NAME}?sslmode=disable&max_conns=20&max_idle_conns=4  # Postgresql
    ports:
      - 4444:4444 # public
      - 4445:4445 # admin
      - 5555:5555 # port for hydra token user
    networks:
      - public
      - postgres
    depends_on:
      hydra-migrate:
        condition: service_completed_successfully

kratos.yml file:

version: v0.11.1

dsn: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST_NAME}:${POSTGRES_PORT}/${KRATOS_DB_NAME}?sslmode=disable&max_conns=20&max_idle_conns=4

identity:
  default_schema_id: customer_v1
  schemas:
    - id: customer_v1
      url: file:///etc/config/kratos/customer.schema.json

log:
  level: debug
  format: text
  leak_sensitive_values: true

serve:
  public:
    base_url: http://localhost:4433/
    cors:
      enabled: true
      debug: true
  admin:
    base_url: http://localhost:4434/

selfservice:
  default_browser_return_url: http://localhost:3000/
  allowed_return_urls:
    - http://localhost:3000
  methods:
    profile:
      enabled: true
    password:
      enabled: true
      config:
        haveibeenpwned_enabled: true
        haveibeenpwned_host: api.pwnedpasswords.com
        max_breaches: 0
        ignore_network_errors: true
        min_password_length: 6
        identifier_similarity_check_enabled: true
    code:
      enabled: true
      config:
        lifespan: 24h
    link:
      enabled: true
      config:
        lifespan: 24h
    lookup_secret:
      enabled: false
    webauthn:
      enabled: false
    oidc:
      enabled: false

  flows:
    login:
      ui_url: http://localhost:3000/login
      lifespan: 15m
    logout:
      after:
        default_browser_return_url: http://localhost:3000/
    registration:
      ui_url: http://localhost:3000/registration
      lifespan: 15m
      after:
        password:
          hooks:
            - hook: session
    settings:
      ui_url: http://localhost:3000/settings
      privileged_session_max_age: 15m
      required_aal: highest_available
      after:
        default_browser_return_url: http://localhost:3000/settings
    recovery:
      enabled: true
      ui_url: http://localhost:3000/recovery
      use: code
      lifespan: 15m
      after:
        hooks:
          - hook: revoke_active_sessions
    verification:
      enabled: true
      ui_url: http://localhost:3000/verification
      use: link
      lifespan: 15m
      after:
        default_browser_return_url: http://localhost:3000/login
    error:
      ui_url: http://localhost:3000/error

oauth2_provider:
  url: http://localhost:4445
  headers: 
    Authorization: Bearer some-token

session:
  lifespan: 1h
  cookie:
    name: ory-session
    persistent: true

secrets:
  cookie:
    - PLEASE-CHANGE-ME-I-AM-VERY-INSECURE
  cipher:
    - 32-LONG-SECRET-NOT-SECURE-AT-ALL

ciphers:
  algorithm: xchacha20-poly1305

hashers:
  algorithm: argon2
  argon2:
    iterations: 3
    memory: 64MB
    parallelism: 4
    key_length: 32
    salt_length: 16
    expected_duration: 500ms
    expected_deviation: 500ms
    dedicated_memory: 512MB

courier:
  smtp:
    connection_uri: smtp://mailhog:1026/?disable_starttls=true

hydra.yml file:

version: v2.0.3

dsn: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST_NAME}:${POSTGRES_PORT}/${HYDRA_DB_NAME}?sslmode=disable&max_conns=20&max_idle_conns=4

log:
  leak_sensitive_values: true
  format: text
  level: debug

serve:
  cookies:
    same_site_mode: Lax

oidc:
  subject_identifiers:
    supported_types:
      - public
      - pairwise
    pairwise:
      salt: youReallyNeedToChangeThis

urls:
  login: http://localhost:3000/login
  logout: http://localhost:3000/logout
  post_logout_redirect: http://localhost:3000/
  consent: http://localhost:3001/consent
  error: http://localhost:3000/error
  self:
    admin: https://localhost:4445/
    public: http://localhost:4444/
    issuer: http://localhost:4444/

ttl:
  access_token: 1h
  refresh_token: 1h
  id_token: 1h
  auth_code: 1h

oauth2:
  expose_internal_errors: true

secrets:
  cookie:
    - youReallyNeedToChangeThis
  system:
    - youReallyNeedToChangexhis

Here is an example response that I receive for a login flow:

{
  "id": "155217b1-3cd0-4ef1-a1d7-329f65b03071",
  "oauth2_login_challenge": null,
  "type": "browser",
  "expires_at": "2023-03-23T05:31:24.562209Z",
  "issued_at": "2023-03-23T05:16:24.562209Z",
  "request_url": "http://localhost:4433/self-service/login/browser",
  "ui": {
    "action": "http://localhost:4433/self-service/login?flow=155217b1-3cd0-4ef1-a1d7-329f65b03071",
    "method": "POST",
    "nodes": [
      {
        "type": "input",
        "group": "default",
        "attributes": {
          "name": "csrf_token",
          "type": "hidden",
          "value": "ogjV/+bvQFp7a8R+9aUR/Nx1podKqCJTh/Zdkmd0EtNwP+hoo71RFmziv6RA2wpqUKftalBOTP/DA12Nj5GJsQ==",
          "required": true,
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {}
      },
      {
        "type": "input",
        "group": "default",
        "attributes": {
          "name": "identifier",
          "type": "text",
          "value": "",
          "required": true,
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1070004,
            "text": "ID",
            "type": "info"
          }
        }
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "password",
          "type": "password",
          "required": true,
          "autocomplete": "current-password",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1070001,
            "text": "Password",
            "type": "info"
          }
        }
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "method",
          "type": "submit",
          "value": "password",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1010001,
            "text": "Sign in",
            "type": "info",
            "context": {}
          }
        }
      }
    ]
  },
  "created_at": "2023-03-23T05:16:24.578615Z",
  "updated_at": "2023-03-23T05:16:24.578615Z",
  "refresh": false,
  "requested_aal": "aal1",
  "instanceOf": "KratosForm"
}

oauth2_login_challenge is null. I'm not sure if it's supposed to return hydra's login_challenge. A successful login only returns a kratos session cookie, no tokens are returned.
Any assistance would be greatly appreciated.

@ellicodan
Copy link

oauth2_login_challenge is null. I'm not sure if it's supposed to return hydra's login_challenge. A successful login only returns a kratos session cookie, no tokens are returned. Any assistance would be greatly appreciated.

I managed to solve my issues. In kratos.yml, oauth2_provider.url needs to be http://hydra:4445 instead of localhost. Another issue was that my secrets.system changed since I initialized my postgres db, so I needed to reset the db.

peturgeorgievv pushed a commit to senteca/kratos-fork that referenced this issue Jun 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat New feature or request.
Projects
None yet
Development

Successfully merging a pull request may close this issue.