22
33This is an _ unofficial_ reference implementation of the User Login and Consent flow of an
44[ Ory Hydra] ( https://github.com/ory ) OAuth 2.0 server written in Java with SpringBoot. This project demos some
5- key features/ flows/integrations and the of OAuth 2.0 Authorization Code Grant flow. It is mean to be a foundation for
6- production implementations, but it is not an exhaustive implementation nor is guaranteed to be secure, bug free, fully
7- tested, or production ready.
5+ key features, flows, and integrations of the OAuth 2.0 Authorization Code Grant flow. It is meant to be a foundation
6+ for production implementations, but it is not an exhaustive implementation nor is it guaranteed to be secure, bug
7+ free, fully tested, or production ready.
88
99Similar reference implementations can be found on
1010the [ Getting Started] ( https://www.ory.sh/docs/getting-started/overview )
@@ -65,19 +65,19 @@ The functional tests for this project run along all other tests with the standar
6565```
6666
6767The functional tests are unique because there is practically no mocking. This makes for a slightly more complicated
68- setup, but it allows us to reproduce scenarios in a context very similar to what would be seen in production, all they
68+ setup, but it allows us to reproduce scenarios in a context very similar to what would be seen in production, all the
6969way from interacting with the UI back to Ory Hydra.
7070
71711 . Using ` @SpringBootTest ` , the application is started on a random port. Note that the application also configures two
7272 extra controllers to help facilitate testing.
73- 2 . A Playwright browser instance is created (this will be shared for all tests).
74- 3 . Before each test, a new Test Container instance of Ory Hydra is started. This instance of Ory Hydra is running with
75- an in memory database.
76- 4 . A Hydra OAuth client is created.
73+ 2 . A Playwright browser instance is created (shared by all tests).
74+ 3 . A single Test Container instance of Ory Hydra is started and shared by every test in the class. It runs with an
75+ in-container SQLite database.
76+ 4 . Before each test, a unique Hydra OAuth client is created. Hydra remembers consent per subject and client, so a
77+ fresh client per test keeps tests isolated on the shared container.
77785 . The Playwright browser loads the ` /oauth2/auth ` endpoint with the client's information.
78796 . The Playwright api is used to interact with the UI just as a user would do.
79807 . Optionally, the code may be exchanged for the token response.
80- 8 . Repeat from Step 3 for each test.
8181
8282The extra controllers created are not ideal but are useful for testing. One of them is a ` ForwardingController ` which
8383helps work around some networking challenges with a circular dependency in configuration between the application and Ory
@@ -89,15 +89,8 @@ provides a hook for the client call back. This allows us to verify that Hydra ac
8989and provides us access to the ` code ` value so that it can be exchanged for the token response.
9090
9191Since the token flow of OAuth is inherently UI driven, it is imperative that the UI be the driver for the tests. To aid
92- with this the ` Playwright ` framework is used. Allows us to use a headless driver to load the UI and use HTML selectors
93- to interact with the loaded page just like a human would.
94-
95- Due to the overhead of Test Containers, the tests are a bit slow and there is likely some optimization that could be
96- made so that the Ory Hydra containers are re-used across each test rather than recreated for each test.
97-
98- #### Playwright
99-
100- #### Test Containers
92+ with this the ` Playwright ` framework is used. It allows us to use a headless driver to load the UI and use HTML
93+ selectors to interact with the loaded page just like a human would.
10194
10295### Running With Local Ory Hydra
10396
@@ -109,18 +102,22 @@ Note: All steps require Docker and some require `jq`. All commands should run re
109102#### Start Hydra And The Reference App
110103
111104```
112- # Pull Hydra
113- docker pull oryd/hydra:v2.0.2
114-
115- # Use the same docker-compose file used by the functional tests to start Hydra
116- # with an in memory database and run the migration sccripts.
117- docker-compose -f ./reference-app/src/test/resources/docker-compose.yml up --build
105+ # Start Hydra with an in-container SQLite database, running the migrations first —
106+ # the same single-container setup the functional tests get from testcontainers-ory-hydra.
107+ docker run --rm --name hydra \
108+ -p 4444:4444 -p 4445:4445 \
109+ -e DSN="sqlite:///tmp/db.sqlite?_fk=true" \
110+ -e SECRETS_SYSTEM=local-dev-secret \
111+ -e URLS_LOGIN=http://localhost:8080/login \
112+ -e URLS_CONSENT=http://localhost:8080/consent \
113+ --entrypoint sh oryd/hydra:v25.4.0 \
114+ -c "hydra migrate sql -e --yes && hydra serve all --dev"
118115
119116# At this point Hydra urls such as http://localhost:4445/admin/clients should be up and running.
120117
121118# Open a new terminal...
122119
123- # Start the Spring app.
120+ # Start the Spring app.
124121./gradlew bootRun
125122
126123# At this point the reference app pages such as localhost:8080/index.html should load.
@@ -138,7 +135,7 @@ Otherwise, follow these instructions to create a client and test it by going thr
138135
139136```
140137# Create a client. Uses the Hydra container to access the Hydra CLI.
141- hydra_client=$(docker-compose -f ./reference-app/src/test/resources/docker-compose.yml exec hydra \
138+ hydra_client=$(docker exec hydra \
142139 hydra create client \
143140 --endpoint http://127.0.0.1:4445 \
144141 --grant-type authorization_code,refresh_token \
@@ -165,15 +162,15 @@ curl -X PATCH \
165162oauth_endpoint="http://localhost:4444/oauth2/auth?\
166163client_id=${hydra_client_id}&\
167164response_type=code&\
168- redirect_uri=${client_redirect_uri_0 }&\
165+ redirect_uri=${hydra_client_redirect_uri_0 }&\
169166scope=openid+offline&\
170167state=123456789"
171168
172169# Print the endpoint.
173170echo $oauth_endpoint
174171
175172# Click on the printed endpoint (or paste it into a browser).
176- # Complete the OAuth flow (by default the hard coded crentials are username: foo@bar.com password: password).
173+ # Complete the OAuth flow (by default the hard coded credentials are username: foo@bar.com password: password).
177174
178175# replace '...' with the `code` query param in the call back.
179176code=...
@@ -185,7 +182,7 @@ curl -X POST \
185182 -d "grant_type=authorization_code" \
186183 -d "code=${code}" \
187184 -d "redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback" \
188- -d "client_id=${code_client_id }" \
185+ -d "client_id=${hydra_client_id }" \
189186 http://127.0.0.1:4444/oauth2/token
190187```
191188
@@ -242,7 +239,7 @@ sequenceDiagram
242239When the code is exchanged the response contains a ` id_token ` key with a JWT string. Additional information about that
243240token can be found [ here] ( https://openid.net/specs/openid-connect-core-1_0.html ) .
244241
245- You can also see how this demo includes how to include "custom" claims that are not part of the OIDC spect .
242+ This demo also shows how to include "custom" claims that are not part of the OIDC spec .
246243Look in the JWT for the value ` example custom claim value ` .
247244
248245Here is an example JWT json:
@@ -365,4 +362,3 @@ instead, use a Gradle composite build:
365362- [ ] Log out
366363- [ ] Add example with Ory Cloud
367364
368- ## Additional Notes
0 commit comments