EU-Compliant Authentication Setup
This guide shows you how to set up authentication that complies with EU regulations (GDPR, Data Protection Directives) using Keycloak, an open-source identity and access management solution.
Why EU-compliant authentication?
GDPR Requirements:
- ✅ Data sovereignty - Keep authentication data in EU
- ✅ User consent management
- ✅ Right to be forgotten
- ✅ Data portability
- ✅ Privacy by design
Keycloak Benefits:
- ✅ Open-source and self-hosted
- ✅ Full control over user data
- ✅ EU data residency compliant
- ✅ Built-in GDPR features
- ✅ Supports multiple protocols (OAuth 2.0, OpenID Connect, SAML)
- ✅ User federation (LDAP, Active Directory)
- ✅ Two-factor authentication
- ✅ Single Sign-On (SSO)
Prerequisites
Before starting:
- ✅ EvoNEST installed and running
- ✅ Docker installed (for Keycloak)
- ✅ Admin access to your server
- ✅ Domain name (for production)
Estimated Time: 60-90 minutes
Architecture overview
┌─────────────┐
│ User │
└──────┬──────┘
│
↓
┌─────────────────────────────────┐
│ EvoNEST (Next.js) │
│ - NextAuth.js │
│ - Keycloak Provider │
└──────┬──────────────────────────┘
│ OpenID Connect
↓
┌─────────────────────────────────┐
│ Keycloak Server │
│ - User Management │
│ - Authentication │
│ - OAuth 2.0 / OpenID Connect │
└──────┬──────────────────────────┘
│
↓
┌─────────────────────────────────┐
│ PostgreSQL (Keycloak DB) │
│ - User data │
│ - Credentials │
│ - Sessions │
└─────────────────────────────────┘Part 1: Setting up Keycloak
Step 1: Install Keycloak with Docker
We'll run Keycloak in a Docker container alongside EvoNEST.
1.1 Create Keycloak configuration
Create a new file: docker-compose.keycloak.yml
version: "3.8"
services:
postgres-keycloak:
image: postgres:15-alpine
container_name: evonest_keycloak_db
restart: unless-stopped
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: keycloak_db_password_change_me
volumes:
- keycloak_postgres_data:/var/lib/postgresql/data
networks:
- evonest_network
keycloak:
image: quay.io/keycloak/keycloak:23.0
container_name: evonest_keycloak
restart: unless-stopped
command: start-dev
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres-keycloak:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak_db_password_change_me
KC_HOSTNAME: localhost
KC_HOSTNAME_PORT: 8080
KC_HTTP_ENABLED: true
KC_HOSTNAME_STRICT_HTTPS: false
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: change_me_admin_password
ports:
- "8080:8080"
depends_on:
- postgres-keycloak
networks:
- evonest_network
networks:
evonest_network:
driver: bridge
volumes:
keycloak_postgres_data:Change Default Passwords!
Replace keycloak_db_password_change_me and change_me_admin_password with strong passwords!
1.2 Start Keycloak
docker compose -f docker-compose.keycloak.yml up -dWait for startup (1-2 minutes). Watch logs:
docker compose -f docker-compose.keycloak.yml logs -f keycloakLook for:
Keycloak 23.0.0 started in Xms.1.3 Access Keycloak admin console
Open browser: http://localhost:8080
Click "Administration Console"
Login with:
- Username:
admin - Password: Your admin password from docker-compose file
- Username:
Step 2: Configure Keycloak realm
A "realm" is a isolated space for managing users and applications.
2.1 Create a new realm
Hover over "Master" (top-left dropdown)
Click "Create Realm"
Configure:
- Realm name:
evonest - Enabled: ✅
- Realm name:
Click "Create"
2.2 Configure realm settings
Go to "Realm settings" (left sidebar)
General tab:
- Display name:
EvoNEST - HTML Display name:
<b>EvoNEST</b> Authentication - User-managed access: ✅ (GDPR - allows users to manage their data)
- Endpoints: Note the OpenID Endpoint Configuration URL
- Display name:
Login tab:
- User registration: ✅ (if you want users to self-register)
- Forgot password: ✅
- Remember me: ✅
- Email as username: ✅ (recommended)
- Require SSL: external requests (for production, change to "all requests")
Email tab (important for user verification):
- From:
noreply@your-domain.com - Host: Your SMTP server
- Port: 587 (or your SMTP port)
- Username: Your SMTP username
- Password: Your SMTP password
- Enable SSL: ✅
- Enable StartTLS: ✅
- From:
Themes tab:
- Customize login page appearance (optional)
Click "Save"
2.3 Test email configuration (optional)
- Scroll to Email tab
- Click "Test connection"
- Enter test email
- Check email inbox
Step 3: Create OAuth client for EvoNEST
3.1 Create client
Go to "Clients" (left sidebar)
Click "Create client"
General Settings:
- Client type: OpenID Connect
- Client ID:
evonest-app - Click "Next"
Capability config:
- Client authentication: ON
- Authorization: OFF
- Standard flow: ✅ (OAuth 2.0 Authorization Code Flow)
- Direct access grants: ✅
- Click "Next"
Login settings:
- Root URL:
http://localhost:3005(development) - Home URL:
http://localhost:3005 - Valid redirect URIs:
http://localhost:3005/api/auth/callback/keycloak http://localhost:3005/* - Valid post logout redirect URIs:
http://localhost:3005 - Web origins:
http://localhost:3005
- Root URL:
Click "Save"
3.2 Get client credentials
Go to "Clients" → "evonest-app"
Click "Credentials" tab
Copy the Client secret - you'll need this!
Save These Values
You need:
- Client ID:
evonest-app - Client Secret: (from Credentials tab)
- Issuer URL:
http://localhost:8080/realms/evonest
Step 4: Configure user attributes (GDPR compliance)
4.1 Set up required user attributes
Go to "Realm settings" → "User profile" tab
Verify these attributes exist:
username- Requiredemail- RequiredfirstName- OptionallastName- Optional
4.2 Add custom attributes (optional)
For EvoNEST-specific data:
Click "Create attribute"
Add attribute:
- Name:
laboratory - Display name: Laboratory
- Validation: None
- Required: No
- Name:
Repeat for other custom fields if needed
4.3 Set up consent screen (GDPR)
Go to "Clients" → "evonest-app"
Settings tab:
- Consent required: ON
- Display client on consent screen: ON
- Consent screen text:
Allow EvoNEST to access your profile information
Click "Save"
This ensures users explicitly consent to data usage (GDPR requirement).
Step 5: Create test user
5.1 Add a user
Go to "Users" (left sidebar)
Click "Add user"
Fill in:
- Username:
testuser - Email:
test@example.com - Email verified: ✅
- First name: Test
- Last name: User
- Enabled: ✅
- Username:
Click "Create"
5.2 Set password
After creating, go to "Credentials" tab
Click "Set password"
Enter:
- Password:
TestPassword123 - Confirm:
TestPassword123 - Temporary: OFF (so user doesn't have to change on first login)
- Password:
Click "Save"
Part 2: Configure EvoNEST for Keycloak
Step 1: Install Keycloak provider
NextAuth already supports Keycloak, no additional packages needed!
Step 2: Update environment variables
2.1 Update .env.local
NEXTAUTH_SECRET=your-existing-secret
# Keycloak Configuration
KEYCLOAK_CLIENT_ID=evonest-app
KEYCLOAK_CLIENT_SECRET=your-client-secret-from-keycloak
KEYCLOAK_ISSUER=http://localhost:8080/realms/evonest2.2 Update .env.development
NEXTAUTH_URL=http://localhost:3005
MONGODB_URI=mongodb://evonest_user:your_password@mongo_dev:27017
STORAGE_PATH='/usr/evonest/file_storage_dev'
# Keycloak
KEYCLOAK_CLIENT_ID=evonest-app
KEYCLOAK_CLIENT_SECRET=your-client-secret-from-keycloak
KEYCLOAK_ISSUER=http://localhost:8080/realms/evonestStep 3: Update NextAuth configuration
3.1 Import Keycloak provider
Open src/app/api/auth/[...nextauth]/options.ts
Add import:
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import KeycloakProvider from "next-auth/providers/keycloak";
import { get_or_create_client } from "@/app/api/utils/mongodbClient";3.2 Add Keycloak to providers
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID!,
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!,
issuer: process.env.KEYCLOAK_ISSUER!,
}),
// Keep other providers if needed...
],3.3 Update callbacks
Add Keycloak user handling:
callbacks: {
async signIn({ user, account, profile }) {
if (account?.provider === "keycloak") {
try {
const client = await get_or_create_client();
const users = client.db("usersdb").collection("users");
// Extract user info from Keycloak
const keycloakProfile = profile as any;
await users.findOneAndUpdate(
{ auth0id: user.id },
{
$set: {
name: user.name || keycloakProfile.preferred_username,
email: user.email,
recentChangeDate: new Date().toISOString()
},
$setOnInsert: {
auth0id: user.id,
role: 'user',
activeDatabase: 'admin',
databases: ['admin'],
logbook: [`${new Date().toISOString()}: user created via Keycloak`]
}
},
{ upsert: true }
);
return true;
} catch (error) {
console.error('Error creating/updating user:', error);
return false;
}
}
// Handle other providers...
return true;
},
async jwt({ token, user, account }) {
if (user) {
token.sub = user.id;
token.role = user.role;
}
return token;
},
async session({ session, token }) {
if (session?.user) {
session.user.sub = token.sub as string;
}
return session;
}
},Step 4: Test Keycloak authentication
4.1 Restart EvoNEST
docker compose -f docker-compose.dev.yml restart4.2 Test login
Go to: http://localhost:3005
Click "Sign in with Keycloak" (or similar text)
You'll be redirected to Keycloak login page
Login with test user:
- Username:
testuser - Password:
TestPassword123
- Username:
Consent screen appears (if enabled):
- Review permissions
- Click "Accept"
Redirected back to EvoNEST, logged in!
4.3 Verify user in database
Check Mongo Express: http://localhost:8081
Go to
usersdb→usersNew user should exist with Keycloak ID
Part 3: GDPR compliance features
Data protection settings
1. User data export (right to data portability)
In Keycloak Admin Console:
"Realm settings" → "User profile"
Enable "Account Console" for users
Users can access:
http://localhost:8080/realms/evonest/accountUsers can download their data as JSON
2. User account deletion (right to be forgotten)
Option A: Self-Service (recommended)
"Realm settings" → "Login"
Enable "Delete account"
Users can delete their own accounts from Account Console
Option B: Admin-Managed
Create an admin interface in EvoNEST to handle deletion requests.
3. Consent management
Already configured with consent screen. Users must explicitly accept.
4. Data retention policies
Configure session timeouts:
"Realm settings" → "Sessions"
Set:
- SSO Session Idle: 30 minutes
- SSO Session Max: 10 hours
- Offline Session Idle: 30 days
5. Audit logging
Enable audit logging:
"Realm settings" → "Events"
Event Listeners:
- Add
jboss-logging
- Add
User Events Settings:
- Save Events: ON
- Expiration: 365 days
- Saved Types: Select all
Click "Save"
View events: "Events" tab shows login history, admin actions, etc.
Part 4: Production deployment
Step 1: Production Keycloak setup
1.1 Update Docker compose for production
Create docker-compose.keycloak.prod.yml:
version: "3.8"
services:
postgres-keycloak:
image: postgres:15-alpine
container_name: evonest_keycloak_db_prod
restart: unless-stopped
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
volumes:
- keycloak_postgres_data_prod:/var/lib/postgresql/data
networks:
- evonest_network
keycloak:
image: quay.io/keycloak/keycloak:23.0
container_name: evonest_keycloak_prod
restart: unless-stopped
command: start --optimized
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres-keycloak:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
KC_HOSTNAME: auth.your-domain.com
KC_HOSTNAME_STRICT: true
KC_HTTP_ENABLED: false
KC_HTTPS_ENABLED: true
KC_PROXY: edge
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
ports:
- "8443:8443"
depends_on:
- postgres-keycloak
networks:
- evonest_network
networks:
evonest_network:
external: true
volumes:
keycloak_postgres_data_prod:1.2 Set up SSL/TLS
Option A: Use Reverse Proxy (Recommended)
Set up Nginx or Traefik with Let's Encrypt:
server {
listen 443 ssl http2;
server_name auth.your-domain.com;
ssl_certificate /etc/letsencrypt/live/auth.your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.your-domain.com/privkey.pem;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Option B: Keycloak with SSL Certificate
Mount certificates in Docker and configure Keycloak to use them.
Step 2: Update production environment
2.1 Create .env.production for Keycloak
KEYCLOAK_DB_PASSWORD=your-strong-db-password
KEYCLOAK_ADMIN_PASSWORD=your-strong-admin-password2.2 Update EvoNEST .env.production
NEXTAUTH_URL=https://your-domain.com
MONGODB_URI=mongodb://evonest_user:password@mongo:27017
STORAGE_PATH='/usr/evonest/file_storage'
# Keycloak Production
KEYCLOAK_CLIENT_ID=evonest-app
KEYCLOAK_CLIENT_SECRET=production-client-secret
KEYCLOAK_ISSUER=https://auth.your-domain.com/realms/evonestStep 3: Update Keycloak client settings
Login to Keycloak Admin Console (production)
Go to "Clients" → "evonest-app"
Update Valid redirect URIs:
https://your-domain.com/api/auth/callback/keycloak https://your-domain.com/*Update Web origins:
https://your-domain.comClick "Save"
Security best practices
1. Strong passwords
- Enforce password policies in Keycloak
- Go to "Authentication" → "Policies"
- Set minimum length, complexity, etc.
2. Two-factor authentication
Enable OTP:
- "Authentication" → "Required Actions"
- Enable "Configure OTP"
- Users will be prompted to set up 2FA on first login
3. Rate limiting
Protect against brute force:
- "Realm settings" → "Security defenses"
- Brute Force Detection:
- Enabled: ON
- Max Login Failures: 5
- Wait Increment: 60 seconds
- Quick Login Check: 1000 milliseconds
4. Regular backups
Backup PostgreSQL database:
docker exec evonest_keycloak_db_prod pg_dump -U keycloak keycloak > keycloak_backup.sqlRestore:
docker exec -i evonest_keycloak_db_prod psql -U keycloak keycloak < keycloak_backup.sql5. Monitor logs
View Keycloak logs:
docker logs evonest_keycloak_prod -fCheck for:
- Failed login attempts
- Unusual access patterns
- Error messages
Troubleshooting
Problem: "Invalid redirect URI"
Cause: Redirect URI mismatch
Solution:
- Check exact URI in error message
- Add to Keycloak client's "Valid redirect URIs"
- Include wildcards:
http://localhost:3005/*
Problem: Keycloak won't start
Check logs:
docker logs evonest_keycloakCommon causes:
- Database not ready (wait longer)
- Port 8080 already in use
- Invalid environment variables
Problem: "Token verification failed"
Causes:
- NEXTAUTH_SECRET not set
- Issuer URL mismatch
- Clock skew between containers
Solutions:
- Verify environment variables
- Check issuer URL matches exactly
- Synchronize system clocks
Problem: Users can't login after migration
Solution:
- Clear browser cookies
- Clear NextAuth session
- Re-login with Keycloak
GDPR compliance checklist
Use this checklist to ensure compliance:
Migration from existing auth
If migrating from Google OAuth or credentials:
Step 1: Run both systems in parallel
Keep existing auth while adding Keycloak:
providers: [
KeycloakProvider({ /* config */ }),
GoogleProvider({ /* existing */ }),
CredentialsProvider({ /* existing */ }),
],Step 2: Migrate users gradually
- Announce migration to users
- Have users login with Keycloak
- Link accounts if needed (custom logic)
Step 3: Deprecate old auth
After migration period:
- Remove old providers
- Update documentation
- Notify remaining users
Next steps
- User Management - Managing roles and permissions
- Security Best Practices - Additional hardening
- Backup and Recovery - Data protection strategies
Additional resources
- Keycloak Documentation: https://www.keycloak.org/documentation
- GDPR Compliance: https://gdpr.eu
- NextAuth.js Keycloak Provider: https://next-auth.js.org/providers/keycloak
Congratulations! You now have a fully EU-compliant authentication system for EvoNEST with complete control over your user data and privacy.