Skip to content

DT-507: Implement production-ready Keycloak JWT authentication with RBAC - #22

Open
devajipatil wants to merge 12 commits into
developfrom
DT-507-backend
Open

DT-507: Implement production-ready Keycloak JWT authentication with RBAC#22
devajipatil wants to merge 12 commits into
developfrom
DT-507-backend

Conversation

@devajipatil

Copy link
Copy Markdown
Collaborator

Overview

This PR enhances the existing Keycloak authentication integration to be production-ready by introducing proper JWT validation, role extraction, and role-based access control (RBAC).

Key Changes

1. JWT Validation Improvements

  • Added JWKS caching with automatic refresh (5 min TTL)
  • Enforced validation for:
    • issuer
    • audience
    • expiration

2. Role-Based Access Control (RBAC)

  • Extract roles from:
    • realm_access.roles
    • resource_access.{client}.roles
  • Introduced reusable role guards:
    • require_user()
    • require_creator()
    • require_admin()

3. New Auth Module Structure

Added:
auth/

  • models.py → AuthenticatedUser model
  • dependencies.py → Role-based guards
  • keycloak_config.py → Improved JWT handling

4. API Security Changes

  • Updated endpoints to use role-based dependencies instead of raw token validation
  • Introduced 403 Forbidden for unauthorized role access

5. Swagger OAuth Improvements

  • Added PKCE support
  • Configured scopes (openid, profile, email)

Why This Change

Previous implementation:

  • Did not validate roles
  • Used static JWKS (breaks on key rotation)
  • Allowed any authenticated user full access

This update aligns the backend with production-grade security standards similar to Spring Boot resource server configuration.

Testing

  • Verified valid token access
  • Verified expired token → 401
  • Verified invalid audience → 401
  • Verified insufficient role → 403

Impact

  • Breaking change: endpoints now require proper roles
  • Existing tokens must include correct role mappings in Keycloak

Next Steps

  • Restrict CORS configuration for production
  • Add integration tests for role-based endpoints

@devajipatil devajipatil self-assigned this Apr 30, 2026
@devajipatil devajipatil added the enhancement New feature or request label Apr 30, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to make backend Keycloak authentication production-ready with JWT validation and RBAC, while also refactoring backend routes/controllers and introducing a large set of frontend dashboard, i18n, dark mode, runtime config, and wizard changes.

Changes:

  • Reworked backend Keycloak auth to validate JWT issuer/audience/signature and added role guard helpers.
  • Split backend routes/controllers out of init.py, with updated CORS and API wiring.
  • Added significant frontend dashboard/UI changes including i18n, dark mode, onboarding, component management, and runtime configuration.

Reviewed changes

Copilot reviewed 46 out of 53 changed files in this pull request and generated 23 comments.

Show a summary per file
File Description
package.json Adds root React Scripts commands.
node_modules/.yarn-integrity Commits local package manager install artifact.
frontend/vite.config.ts Changes dev server host/port and adds cookie-clearing middleware.
frontend/tsconfig.node.json Removes erasableSyntaxOnly.
frontend/tsconfig.app.json Removes erasableSyntaxOnly.
frontend/tailwind.config.js Enables class-based dark mode.
frontend/src/types/index.ts Adds dashboard/component types and tightens config typing.
frontend/src/runtime-config.ts Adds runtime/env/fallback config resolution.
frontend/src/main.tsx Wraps app in i18n provider.
frontend/src/index.css Adds global layout and dark-mode styles.
frontend/src/i18n.tsx Adds English/German translation provider.
frontend/src/config.js Updates runtime API/keycloak defaults.
frontend/src/components/Tooltip.tsx Adds shared tooltip component.
frontend/src/components/StatsCard.tsx Adds tooltip and dark-mode support.
frontend/src/components/Sidebar.tsx Reworks navigation with i18n, help, tooltips, and mobile behavior.
frontend/src/components/OnboardingGuide.tsx Adds onboarding guide modal.
frontend/src/components/Header.tsx Adds language/theme/help/menu controls.
frontend/src/components/DeploymentWizard.tsx Replaces connector deployment wizard with simplified flow.
frontend/src/components/DeleteModal.tsx Makes delete modal labels/message configurable.
frontend/src/components/ConnectorTableNew.tsx Adds mobile card rendering.
frontend/src/components/ConnectorTable.tsx Changes delete identifier and responsive table spacing.
frontend/src/components/ConnectorsManager.tsx Adds new connector management UI.
frontend/src/components/ComponentWizard.tsx Adds component/service wizard.
frontend/src/components/ComponentsManager.tsx Adds component/service management UI.
frontend/src/components/AddComponentDialog.tsx Adds add-item selection dialog.
frontend/src/auth/keycloak.ts Reads Keycloak settings from runtime config.
frontend/src/api/client.ts Reads API base URL/key from runtime config.
frontend/package.json Adds dev dependencies and loosens TypeScript range.
frontend/package-lock.json Updates lockfile for frontend dependency changes.
frontend/.env.example Formatting-only newline change.
frontend/.env Replaces placeholders with staging values.
docs/user-guide/README.md Updates SDE URL example.
backend/utilities/auth_utils.py Hardens OAuth token request handling.
backend/routes/submodel.py Adds submodel router.
backend/routes/health.py Adds health router.
backend/routes/connectors.py Adds connector router.
backend/routes/config.py Adds config/dataspace router.
backend/init.py Includes routers and moves CORS setup.
backend/controllers/submodel_controller.py Adds submodel controller logic.
backend/controllers/health_controller.py Adds health controller logic.
backend/controllers/connectors_controller.py Adds connector controller logic.
backend/controllers/config_controller.py Adds config/dataspace controller logic.
backend/config/configuration.yml Updates configured SDE URL.
backend/auth/models.py Adds authenticated user model.
backend/auth/keycloak_config.py Reworks Keycloak JWT validation and Swagger OAuth config.
backend/auth/dependencies.py Adds reusable RBAC guard dependencies.
.vscode/settings.json Adds workspace Python REPL setting.
.gitignore Ignores history and node modules.
.github/workflows/codeql.yml Removes CodeQL fail-on: error.
Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/routes/connectors.py Outdated
Comment on lines +25 to +47
from controllers.connectors_controller import *

router = APIRouter(tags=["EDC"])

@router.get("/api/connectors")
async def list_connectors(request: Request):
return await list_connectors(request)

@router.get("/api/connectors/{connector_id}")
async def get_connector(connector_id: int, user=Depends(keycloak_openid.get_current_user)):
return await get_connector(connector_id, user)

@router.post("/api/connector")
async def add_connector(connector, request: Request):
return await add_connector(connector, request)

@router.put("/api/connectors/{connector_id}")
async def upgrade_connector(connector_id: str, connector, request: Request):
return await upgrade_connector(connector_id, connector, request)

@router.delete("/api/connectors/{connector_name}")
async def delete_connector(connector_name: str, request: Request):
return await delete_connector(connector_name, request) No newline at end of file
Comment thread backend/routes/submodel.py Outdated
Comment on lines +25 to +35
from controllers.submodel_controller import *

router = APIRouter(tags=["Submodel"])

@router.post("/api/submodel")
async def add_submodel_service(data: dict, user=Depends(keycloak_openid.get_current_user)):
return await add_submodel_service(data, user)

@router.post("/api/submodel/{submodel_service_id}")
async def add_existing_submodel_service(data: dict, user=Depends(keycloak_openid.get_current_user)):
return await add_existing_submodel_service(data, user) No newline at end of file
Comment thread backend/routes/config.py Outdated
Comment on lines +25 to +35
from controllers.config_controller import *

router = APIRouter()

@router.get("/api/config")
async def get_config(user=Depends(keycloak_openid.get_current_user)):
return get_config(user)

@router.get("/api/dataspace")
async def get_dataspace_settings(request: Request):
return get_dataspace_settings(request) No newline at end of file
Comment thread backend/init.py
Comment thread backend/auth/keycloak_config.py
Comment thread .github/workflows/codeql.yml
Comment thread node_modules/.yarn-integrity Outdated
Comment on lines +1 to +21
{
"systemParams": "darwin-arm64-131",
"modulesFolders": [
"node_modules"
],
"flags": [],
"linkedModules": [],
"topLevelPatterns": [
"keycloak-js@^26.2.0",
"react-router-dom@^7.9.3"
],
"lockfileEntries": {
"cookie@^1.0.1": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
"keycloak-js@^26.2.0": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.0.tgz",
"react-router-dom@^7.9.3": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.3.tgz",
"react-router@7.9.3": "https://registry.npmjs.org/react-router/-/react-router-7.9.3.tgz",
"set-cookie-parser@^2.6.0": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz"
},
"files": [],
"artifacts": {}
} No newline at end of file
Comment thread package.json Outdated
Comment thread frontend/src/components/DeploymentWizard.tsx
Comment thread backend/init.py
Copilot AI requested a review from saudkhan116 June 9, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants