Skip to content

Commit

Permalink
feat: hydra integration
Browse files Browse the repository at this point in the history
chore: renaming folder

chore: moving some of the change to the rest layer instead of graphql

chore: some iteration on hydra

feat: adding scope middleware

chore: testing client credentials

chore: adding appId to know whether a request comes from hydra or kratos

chore: update docs

fix: test?
  • Loading branch information
Nicolas Burtey committed Sep 14, 2023
1 parent fc27d2f commit 7423e5d
Show file tree
Hide file tree
Showing 21 changed files with 400 additions and 23 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ kill-graphql:
redis-cli:
docker-compose exec redis redis-cli

redis-flush:
docker-compose exec redis redis-cli FLUSHDB

codegen:
yarn write-sdl

Expand Down
22 changes: 22 additions & 0 deletions dev/ory/hydra.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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:3000/login
logout: http://127.0.0.1:3000/logout

secrets:
system:
- youReallyNeedToChangeThis

oidc:
subject_identifiers:
supported_types:
- pairwise
- public
pairwise:
salt: youReallyNeedToChangeThis
14 changes: 13 additions & 1 deletion dev/ory/oathkeeper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ authenticators:
subject_from: identity.id
extra_from: identity.traits

oauth2_introspection:
enabled: true
config:
introspection_url: http://hydra:4445/admin/oauth2/introspect
token_from:
header: Oauth2-Token

oauth2_client_credentials:
enabled: true
config:
token_url: http://hydra:4444/oauth2/token

anonymous:
enabled: true
config:
Expand Down Expand Up @@ -60,7 +72,7 @@ mutators:
config:
jwks_url: file:///home/ory/jwks.json
issuer_url: "galoy.io"
claims: '{"sub": "{{ print .Subject }}" }'
claims: '{"sub": "{{ print .Subject }}", card: "{{ print .Ext.card }}" }'

noop:
enabled: true
Expand Down
21 changes: 18 additions & 3 deletions dev/ory/oathkeeper_rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@
preserve_query: true
subject_from: identity.id
extra_from: "@this"

- handler: oauth2_introspection
config:
introspection_url: http://hydra:4445/admin/oauth2/introspect
token_from:
header: Oauth2-Token

- handler: bearer_token
config:
check_session_url: http://kratos:4433/sessions/whoami
Expand All @@ -72,10 +79,11 @@
- handler: anonymous
authorizer:
handler: allow

mutators:
- handler: id_token
config:
claims: '{"sub": "{{ print .Subject }}", "session_id": "{{ print .Extra.id }}", "expires_at": "{{ print .Extra.expires_at }}" }'
config: #! TODO: add aud: {"aud": ["https://api/graphql"] }
claims: '{"sub": "{{ print .Subject }}", "session_id": "{{ print .Extra.id }}", "expires_at": "{{ print .Extra.expires_at }}", "scope": "{{ print .Extra.scope }}", "client_id": "{{ print .Extra.client_id }}" }'

- id: admin-backend
upstream:
Expand All @@ -85,6 +93,13 @@
url: "<(http|https)>://<.*><[0-9]+>/admin<.*>"
methods: ["GET", "POST", "OPTIONS"]
authenticators:
# - handler: oauth2_client_credentials
# config:
# token_url: http://hydra:4444/oauth2/token
# required_scope:
# - admin
# - editor

- handler: cookie_session
config:
check_session_url: http://kratos:4433/sessions/whoami
Expand All @@ -104,5 +119,5 @@
handler: allow
mutators:
- handler: id_token
config:
config: #! TODO: add aud: {"aud": ["https://api/admin/graphql"] }
claims: '{"sub": "{{ print .Subject }}"}'
4 changes: 4 additions & 0 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,7 @@ services:
- "8071:8071"
extra_hosts:
- "bats-tests:host-gateway"
hydra:
ports:
- "4444:4444" #! Public port
- "4445:4445" #! Admin port
34 changes: 34 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ services:
- lnd-outside-1
- svix
- lnd-outside-2
- hydra
- mailslurper
restart: on-failure:10
integration-deps:
image: busybox
Expand Down Expand Up @@ -422,3 +424,35 @@ services:
image: postgres:14.1
environment:
POSTGRES_PASSWORD: postgres
hydra:
image: oryd/hydra:v2.1.2
command: serve -c /home/ory/hydra.yml all --dev
volumes:
- type: bind
source: dev/ory
target: /home/ory
environment:
- DSN=postgres://hydra:secret@postgresdhydra:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4
restart: unless-stopped
depends_on:
- hydra-migrate
- postgresdhydra
ports: []
hydra-migrate:
image: oryd/hydra:v2.1.2
environment:
- DSN=postgres://hydra:secret@postgresdhydra:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4
command: migrate -c /home/ory/hydra.yml sql -e --yes
volumes:
- type: bind
source: dev/ory
target: /home/ory
restart: on-failure
depends_on:
- postgresdhydra
postgresdhydra:
image: postgres:14.1
environment:
- POSTGRES_USER=hydra
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=hydra
132 changes: 132 additions & 0 deletions docs/hydra.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// TODO: PKCE flow (for alby like client, or mobile client)
// TODO: login flow with cookie
// TODO: add/use email instead of phone

Make sure you have `hydra` command line installed

```sh
brew install ory-hydra
```

# run the experiment:

Follow the instructions below


On console 1:

launch the hydra login consent node, which will provide the authentication (interactive with kratos API) and consent page.

```sh
hydra-login-consent-node % npm start
```

On console 2:
```sh
galoy % make start
```

On console 3:
Follow the instructions below


## create a OAuth2 client

Think of the client as the service that need to get the delegation access

If you use concourse, you, as the end user, will login with Google Workspace.
The client is concourse in this example.

For the galoy stack, some examples of clients could be Alby, a boltcard service, a nostr wallet connect service, an accountant that access the wallet in read only.


```sh
code_client=$(hydra create client \
--endpoint http://127.0.0.1:4445 \
--grant-type authorization_code,refresh_token \
--response-type code,id_token \
--format json \
--scope offline --scope transactions:read --scope payments:send \
--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')
```

to do a PKCE session, add `--token-endpoint-auth-method none`

## Initiate the request

this simulate the front end client.
would be mobile app for adding a boltcard

```sh
hydra perform authorization-code \
--client-id $code_client_id \
--client-secret $code_client_secret \
--endpoint http://127.0.0.1:4444/ \
--port 5555 \
--scope offline --scope transactions:read --scope payments:send
```

do the login and consent

copy the Access token to the mobile app.

you are now connect as the user when you add the Header `Oauth2-Token: {token}`. (not that Bearer should not be present, unlike for the Authorization header. seems to a oathkeeper quirks)

### debug

hydra introspect token \
--format json-pretty \
--endpoint http://127.0.0.1:4445/ \
$ory_at_TOKEN
# OR
curl -X POST http://localhost:4445/admin/oauth2/introspect -d token=$ory_at_TOKEN

curl -I -X POST http://localhost:4456/decisions/graphql -H "Oauth2-Token: $ory_at_TOKEN"

curl --location 'http://localhost:4002/graphql' \
--header 'Content-Type: application/json' \
--header "Oauth2-Token: $ory_at_TOKEN" \
--data '{"query":"query me {\n me {\n id\n defaultAccount {\n id\n }\n }\n}","variables":{}}'


## client_credentials

#### create client

```
client=$(hydra create client \
--endpoint http://127.0.0.1:4445/ \
--format json \
--grant-type client_credentials \
--scope editor \
--scope admin)
client_id=$(echo $client | jq -r '.client_id')
client_secret=$(echo $client | jq -r '.client_secret')
```

#### get token for client

```
hydra perform client-credentials \
--endpoint http://127.0.0.1:4444/ \
--client-id $client_id \
--client-secret $client_secret \
--scope editor \
--scope admin
```

// could be a great option to use oauth2_client_credentials oathkeeper authentication
// but the response is not returning the scope in the jwt
curl -s -I -X POST http://localhost:4456/decisions/graphql --user $client_id:$client_secret


## list OAuth 2.0 consent

export subject=092fbf63-0b3a-422f-8260-b6f0720bf4ad
curl http://localhost:4445/admin/oauth2/auth/sessions/consent?subject=$subject

curl 'http://localhost:4445/admin/oauth2/auth/sessions/consent?subject=092fbf63-0b3a-422f-8260-b6f0720bf4ad'
38 changes: 38 additions & 0 deletions docs/hydra.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
terraform {
required_providers {
hydra = {
source = "svrakitin/hydra"
version = "0.1.4"
}
}
}

provider "hydra" {
endpoint = "http://localhost:4445"
}

resource "hydra_oauth2_client" "example" {
client_name = "example"
redirect_uris = ["http://localhost:8080/callback"]
response_types = ["code"]
token_endpoint_auth_method = "none"
}

output "example_client_id" {
description = "The client ID of the example OAuth2 client."
value = hydra_oauth2_client.example.client_id
}

output "example_client_secret" {
description = "The client secret of the example OAuth2 client."
value = hydra_oauth2_client.example.client_secret
sensitive = true
}

resource "hydra_oauth2_client" "example2" {
client_name = "example2"
grant_types = ["client_credentials"]
redirect_uris = ["http://localhost:8080/callback"]
response_types = ["token"]
token_endpoint_auth_method = "client_secret_basic"
}
4 changes: 4 additions & 0 deletions quickstart/galoy/docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,7 @@ services:
- "8071:8071"
extra_hosts:
- "bats-tests:host-gateway"
hydra:
ports:
- "4444:4444" #! Public port
- "4445:4445" #! Admin port
4 changes: 3 additions & 1 deletion src/app/authentication/index.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ type AddEmailToIdentityResult = {
type LoginWithEmailResult = {
authToken: AuthToken
totpRequired: boolean
id?: UserId
}

type LoginWithPhoneResult = {
type LoginWithPhoneTokenResult = {
authToken: AuthToken
totpRequired: boolean
id: UserId
}

type LoginWithEmailCookieResult = {
Expand Down
Loading

0 comments on commit 7423e5d

Please sign in to comment.