5.1 Concepts and Architecture

Explore the sample application, end-to-end security flow, and the Oracle Deep Data Security (Deep Sec) capabilities you'll implement.

About the sample application

In this chapter, you'll deploy the Employee Records API, which is a sample Spring Boot REST API serving employee data from a Human Resources (hr) schema. The application does not contain any custom access-control code. Instead, it relies entirely on Deep Sec data grants to determine which rows and columns a user can see, with the Oracle JDBC Spring Boot provider handling all security context propagation automatically.

The API exposes two endpoints:
  • GET /api/employees: Returns the signed-in employee’s own record. Access is controlled by the data role, EMPLOYEE_ROLE, which filters rows based on the user’s email.
  • GET /api/employees/salary-summary: Returns team-wide aggregate salary statistics (min, max, average, count). The application temporarily activates the COMPENSATION_ANALYST data role for the duration of the API call, securely calculating aggregates without exposing the individual salaries of other employees.

The end-to-end flow

In this application scenario, a client (curl) sends requests to the Spring Boot REST API, which then connects to Oracle AI Database.

The end-to-end security flow works as follows:
  1. End-user authentication: The end user authenticates to Microsoft Entra ID using the OAuth 2.0 authorization-code flow with Proof Key for Code Exchange (PKCE) and obtains an access token.
  2. API request: The user calls the Spring Boot REST API, passing the access token in the authorization header.
  3. End-user token validation: Spring Security validates the incoming end-user token against Entra ID.
  4. Database-access token acquisition: The Oracle JDBC Spring Boot provider uses the application's client credentials (client ID and client secret) to obtain a database-scoped access token from Entra ID. This occurs at pool initialization and on token refresh.
  5. Connection pool authentication: The provider authenticates the application's connection pool user account to the database using the database-access token.
  6. Security context payload propagation: On each request, the Spring Boot provider reads the end-user’s JWT from the Spring Security context and attaches it to the database connection, along with the application’s database-access token. Together, these form the end-user security context payload.
  7. Database enforcement: The database validates both tokens. It validates the database-access token and authorizes the application connection. It validates the end-user token and establishes the end-user security context, enabling the user’s data roles (that are mapped to external application roles) and corresponding data grants. The database returns only the rows and columns the user is authorized to see.
  8. Privilege elevation: For the salary-summary endpoint, the application temporarily activates an additional data role (COMPENSATION_ANALYST) through the @RunWithDataRoles annotation present in the application’s code. This elevation is scoped to a single method call and deactivated automatically afterward.

What you'll implement

You'll implement two key security capabilities of Deep Sec in this quick start:
  • Security context propagation using only configuration changes (GET /api/employees): You'll configure the Oracle JDBC Spring Boot provider to automatically propagate the end-user security context payload to the database without making any application code changes.
  • Dynamic privilege elevation (GET /api/employees/salary-summary): You'll implement temporary privilege elevation so the application can perform restricted operations on behalf of end users without permanently granting those privileges. The sample application already includes the required code for this; however, if you were building your own application, adding the @RunWithDataRoles annotation to the target method would be your only application code change.
    • How it works: In the database, you'll create a data role as disabled and a corresponding data grant. You then grant this data role exclusively to the application identity so that only the application can enable it. At runtime, the application activates the data role using the @RunWithDataRoles annotation in its code. For the /api/employees/salary-summary endpoint, the service method in EmployeeService.java is decorated with the @RunWithDataRoles annotation. This method runs with the COMPENSATION_ANALYST data role whenever it is called:
      @RunWithDataRoles(
              dataRoles = {"COMPENSATION_ANALYST"}
      )
      @Transactional(readOnly = true)
      public SalarySummaryDto getSalarySummary() {
          ...
      }
      The framework keeps the data role active for the duration of this single method call and automatically deactivates it when the method returns.
    • Why it matters: By scoping elevated privileges to specific operations rather than granting them permanently to end users, you tightly confine access, limit exposure to AI-generated SQL, and significantly reduce the risk of SQL injection attacks.

    See Privilege Elevation.