OHDSI / OHDSI/WebAPI

WebAPI Security & Authorization Model Proposal (Spring Security, JDK 21)

Open
#2,476 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
151
Forks
183
Avg merge
14m
Merged PRs (30d)
2

Description

WebAPI Authorization Model Proposal (Spring Security, JDK 21)

Background

As part of the WebAPI 3.0 modernization effort (JDK 21, Spring Boot 3.5), we are redesigning the authorization layer while migrating away from Apache Shiro toward pure Spring Security.

The current Shiro-based model is largely HTTP path–driven, which has resulted in:

  • One permission per endpoint
  • Tight coupling between REST structure and authorization
  • Difficulty expressing business-level functions
  • High maintenance overhead as endpoints evolve

This issue proposes a function-centric, capability-based authorization model that better fits WebAPI’s collaboration and security needs.

Goals

  • Authorize functions, not endpoints
  • Avoid permission explosion
  • Support entity ownership and fine-grained sharing
  • Scale cleanly in both data size and performance
  • Maintain strong referential integrity
  • Integrate naturally with Spring Security
  • Support both global roles and per-entity access

Core Concepts

Capabilities vs Entity Access

Authorization is separated into two additive mechanisms:

  1. Global capability permissions
  2. Entity-specific permissions

Either mechanism can independently grant access.

Wildcard entity permissions such as read:cohort:12 are explicitly avoided.

Global Capability Permissions

Capabilities are stored as Spring Security authorities.

Permission format:

<action>:<scope>

Examples:

  • create:cohort
  • read:cohort
  • write:conceptset
  • report:generate
  • report:view
  • admin:*

Capabilities grant broad authority and do not reference entity IDs.

Entity-Specific Permissions

Entity-level access is stored in entity-specific permission tables, one per entity type.

These permissions allow fine-grained sharing without granting global authority.

Authorization Model (Additive)

Access to an entity is granted if any of the following is true:

  • User has the relevant global capability
  • User owns the entity
  • User has an entity-level permission grant

Capabilities do not gate entity permissions.

Read Authorization Logic
canReadEntity(user, entity) =
  has read:<entity>
  OR is owner
  OR has READ permission
Write Authorization Logic
canWriteEntity(user, entity) =
  has write:<entity>
  OR is owner
  OR has WRITE permission

Actions

  • create – create a new entity
  • read – read an entity definition
  • write – modify or delete an entity
  • report:generate – execute analyses that generate results
  • report:view – view or fetch generated results
  • admin – administrative/system actions

Removed Permission Patterns

The following patterns do not exist:

  • read:cohort:12
  • write:conceptset:*
  • read:*:123

This prevents permission explosion and orphaned permissions.

Entity Access Control Model

Each entity type defines its own permission table.

Example: Cohort Definition Permissions
cohort_definition_permission
- id
- cohort_id (FK -> cohort_definition.id)
- user_id (FK -> sec_user.id)
- permission_type (READ, WRITE)
Example: Concept Set Permissions
concept_set_permission
- id
- concept_set_id (FK -> concept_set.id)
- user_id (FK -> sec_user.id)
- permission_type (READ, WRITE)

Ownership rules:

  • Creators receive WRITE
  • Owners implicitly have READ
  • Ownership is not stored as a permission row

Listing Entities

There is no separate list permission.

List endpoints return only entities the user can read, based on:

  • Global read capability
  • Ownership
  • Entity-level permission

Admin Permissions

admin:* includes:

  • Source management
  • Cache clearing
  • System configuration
  • Background task control
  • Operational maintenance

Admins may bypass entity-level permission checks where appropriate.

Performance Considerations

  • Capability checks are in-memory
  • Ownership checks are simple FK comparisons
  • Entity permission checks are indexed lookups
  • No wildcard parsing
  • No polymorphic joins

Why Spring Security

Spring Security provides:

  • Active maintenance
  • First-class Spring Boot support
  • Method-level authorization
  • OAuth/JWT integration
  • Strong ecosystem alignment

Shiro is endpoint-centric, encourages wildcard permissions, and is poorly aligned with Spring Boot 3.x.

Summary

  • Migrate to Spring Security
  • Use function-centric capabilities
  • Use additive authorization
  • Separate global and entity permissions
  • Avoid wildcard entity permissions
  • Use entity-specific permission tables
  • Separate reporting permissions as report:*

Next Steps

  • Implement authorization services
  • Add Spring Security AuthorizationManagers
  • Replace Shiro configuration
  • Design migration strategy

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the current Shiro configuration and the proposed authorization services and Spring Security AuthorizationManagers described in the issue. The work is not ready for a first implementation until the migration strategy and concrete acceptance criteria for replacing Shiro are defined.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring, spring-boot
Domain
authorization, backend-api-design, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.