This repository contains a complete Docker Compose setup for running Ory Kratos (identity management) and Ory Hydra (OAuth2/OpenID Connect server) with full integration between both services. This setup provides a production-ready foundation for identity and OAuth2/OIDC workflows.
- Ory Kratos: Identity and user management with OAuth2 provider integration
- Ory Hydra: OAuth2 and OpenID Connect provider
- PostgreSQL: Separate databases for Kratos and Hydra
- Kratos Self-Service UI: Web interface for user registration, login, and account management
- MailSlurper: Email testing server for development
- β Complete OAuth2/OIDC Integration: Kratos and Hydra work seamlessly together
- β User Registration & Login: Full self-service user management
- β Session Management: Integrated session handling between services
- β Email Verification: Automated email verification workflows
- β Password Recovery: Self-service password reset
- β Multi-Factor Authentication: TOTP and backup codes support
- β CORS Configuration: Properly configured for frontend integration
- β Development Ready: Optimized for local development with debugging
./setup-oauth-integration.shThis script will:
- Start all services with Docker Compose
- Wait for services to be ready
- Initialize OAuth2 clients
- Run integration tests
- Display service URLs and usage instructions
-
Start all services:
docker-compose up -d
-
Wait for services to be ready, then initialize OAuth2 clients:
./init-clients.sh
-
Test the integration:
./test-oauth-integration.sh
- Self-Service UI: http://127.0.0.1:3000
- Kratos Public API: http://127.0.0.1:4433
- Kratos Admin API: http://127.0.0.1:4434
- Hydra Public API: http://127.0.0.1:4444
- Hydra Admin API: http://127.0.0.1:4445
- MailSlurper Web UI: http://127.0.0.1:4437
Use the included client management helper:
# List all OAuth2 clients
./manage-oauth-clients.sh list
# Create different types of clients
./manage-oauth-clients.sh create spa --name "My SPA" --redirect-uri "http://localhost:8080/callback"
./manage-oauth-clients.sh create web --name "My Web App" --secret "my-secret"
./manage-oauth-clients.sh create mobile --name "My Mobile App"
./manage-oauth-clients.sh create service --name "My API Service"
# Get client details
./manage-oauth-clients.sh get [client-id]
# Delete a client
./manage-oauth-clients.sh delete [client-id]Browser β Kratos Self-Service UI (Port 3000)
β
User registers/logs in β Kratos creates session
β
Session stored and managed by Kratos
App β Hydra Authorization Endpoint (Port 4444)
β
Hydra β Kratos Login UI (if user not authenticated)
β
User logs in β Kratos validates credentials
β
Kratos β Hydra (user authenticated)
β
Hydra β App (authorization code)
β
App β Hydra Token Endpoint (exchange code for tokens)
β
Hydra returns access_token, id_token, refresh_token
http://127.0.0.1:4444/oauth2/auth?
client_id=YOUR_CLIENT_ID&
response_type=code&
scope=openid%20email%20profile&
redirect_uri=http://127.0.0.1:3000/auth/callback&
state=random-state-value
oauth2_provider:
url: http://hydra:4444
override_return_to: true
headers:
X-Forwarded-Proto: httpsession:
lifespan: 24h
earliest_possible_extend: 1h
cookie:
domain: 127.0.0.1
same_site: LaxThe identity schema now includes additional fields for better OAuth2 integration:
- Email (required, used for authentication)
- Name (first and last)
- Username (optional)
- Profile picture (optional)
./test-oauth-integration.shThis script tests:
- Service health checks
- OAuth2 client creation
- Authorization endpoint accessibility
- Registration and login flow initiation
- CORS configuration
-
Register a new user:
- Go to http://127.0.0.1:3000
- Click "Sign Up"
- Enter email and password
- Check MailSlurper for verification email
-
Test OAuth2 flow:
- Use the authorization URL from the test script
- Complete login if not already authenticated
- Verify redirect with authorization code
// Initiate OAuth2 flow
const authUrl = `http://127.0.0.1:4444/oauth2/auth?` +
`client_id=YOUR_CLIENT_ID&` +
`response_type=code&` +
`scope=openid email profile&` +
`redirect_uri=${encodeURIComponent('http://localhost:8080/callback')}&` +
`state=${generateRandomState()}`;
window.location.href = authUrl;
// Handle callback and exchange code for tokens
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const state = urlParams.get('state');
if (code) {
const tokenResponse = await fetch('http://127.0.0.1:4444/oauth2/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: 'http://localhost:8080/callback',
client_id: 'YOUR_CLIENT_ID',
// client_secret: 'YOUR_SECRET' // Only for confidential clients
})
});
const tokens = await tokenResponse.json();
// Use tokens.access_token, tokens.id_token, tokens.refresh_token
}const express = require('express');
const axios = require('axios');
const app = express();
// Verify token with Hydra
app.get('/protected', async (req, res) => {
const token = req.headers.authorization?.replace('Bearer ', '');
try {
const response = await axios.post('http://127.0.0.1:4445/admin/oauth2/introspect', {
token: token
});
if (response.data.active) {
res.json({ message: 'Access granted', user: response.data });
} else {
res.status(401).json({ error: 'Invalid token' });
}
} catch (error) {
res.status(401).json({ error: 'Token verification failed' });
}
});# All services
docker-compose logs -f
# Specific service
docker-compose logs -f kratos
docker-compose logs -f hydra
docker-compose logs -f kratos-selfservice-ui# Kratos health
curl http://127.0.0.1:4433/health/ready
# Hydra health
curl http://127.0.0.1:4444/health/ready# Kratos database
docker exec -it kratos-postgres psql -U kratos -d kratos
# Hydra database
docker exec -it hydra-postgres psql -U hydra -d hydraFor production deployment:
- Change all default secrets and passwords
- Enable SSL/TLS for all services
- Configure proper CORS policies
- Use production-grade databases with proper backup
- Set up proper networking and firewalls
- Enable audit logging
- Configure rate limiting
- Use secure cookie settings
# Reset everything
docker-compose down -v && docker-compose up -d
# List Kratos identities
docker exec kratos kratos list identities --endpoint http://127.0.0.1:4434
# Create custom OAuth2 client
docker exec hydra hydra create oauth2-client \
--endpoint http://127.0.0.1:4445 \
--name "Custom Client" \
--secret "custom-secret" \
--grant-type authorization_code,refresh_token \
--response-type code,id_token \
--scope openid,email,profile \
--redirect-uri http://localhost:8080/callback
# Get OAuth2 client details
docker exec hydra hydra get oauth2-client CLIENT_ID --endpoint http://127.0.0.1:4445This repository includes a complete Go application that demonstrates OAuth2 integration with your Ory Hydra setup.
- π Complete OAuth2 Authorization Code flow
- π« Access token, refresh token, and ID token handling
- π Token refresh functionality
- π€ User info endpoint integration
- π₯ Health checks for Ory services
- π Token introspection
- π Web interface for easy testing
# Setup and build the Go client
./setup-go-client.sh
# Run the Go client (automatically gets client ID)
make run-go-client
# Or manually with specific client ID
export CLIENT_ID=$(docker exec hydra hydra list oauth2-clients --endpoint http://127.0.0.1:4445 --format json | jq -r '.[0].client_id')
cd go-client && ./hydra-client- Web Interface: http://127.0.0.1:8080
- Health Check: http://127.0.0.1:8080/api/health
- Login Flow: http://127.0.0.1:8080/login
# Test the Go client
./test-go-client.sh
# Available Make commands
make setup-go-client # Setup Go OAuth2 client
make test-go-client # Test Go OAuth2 client
make run-go-client # Run Go OAuth2 clientSee go-client/README.md for detailed Go client documentation.