The Oracle Database MCP Toolkit — Enabling OAuth 2.0 Authentication in HTTP Streamable Mode
Key Takeaways
- Running the Oracle Database MCP Toolkit over HTTPS without authentication is a valid starting point for development. However, a production deployment must restrict access via OAuth 2.0 if possible.
- The toolkit’s HTTP Streamable mode integrates with any standards-compliant OAuth 2.0 authorization server through two JVM system properties: the issuer URI (used for token discovery) and the JWK Set URI (used for JWT signature verification), and no code changes are required.
- The OAuth 2.0 flow for machine-to-machine scenarios — the one relevant here — is the Client Credentials grant. Clients obtain a Bearer token from the authorization server and attach it to every MCP request via the Authorization: Bearer <token> header.
- Once authentication is active, any request that is missing or includes invalid authentication tokens will be rejected with HTTP 401, protecting your Oracle Database tools from unauthorized access.
Introduction
In my previous blog posts, I first introduced the Oracle Database MCP Toolkit and how to run it in local STDIO mode. Then, I explained how to expose the MCP server over a network using HTTPS in HTTP Streamable mode.
Next, I presented how to implement authentication using a static token scheme. This blog post will explore how to use OAuth 2.0 to enforce authentication, which is better aligned with enterprise, production-grade deployments.
We will add OAuth 2.0 authentication to the server we already have running, set up a local authorization server using the Spring Authorization Server, obtain a bearer token, and test it all to confirm if the server correctly rejects unauthenticated requests while accepting authenticated ones.
So without further ado, let’s get started!
Prerequisites
- Oracle Database MCP Toolkit
- JDK — Java Development Kit
- Oracle AI Database 26ai Free Container Image
- Your preferred Java IDE — Eclipse, IntelliJ, VS Code
- Apache Maven
- The curl CLI tool or your preferred HTTP client
- Oracle Database details, such as JDBC URL, DB_USERNAME, and DB_PASSWORD
Steps to Enable OAuth 2.0 Authentication
Step 1: Understanding the Authentication Architecture
Before we write a single command, it helps to have a clear picture of what we are building. When authentication is enabled, the Oracle Database MCP Toolkit acts as an OAuth 2.0 Resource Server.
It does not issue tokens — it only validates them. Token issuance is the job of a separate Authorization Server (also called an Identity Provider or IdP).
The flow at runtime looks like this:
The Oracle Database MCP Toolkit needs two additional configuration parameters to perform token validation:
- -Dauth.issuerUri — The issuer URL of your OAuth 2.0 authorization server.
The toolkit uses this to discover the server’s OpenID
Connect metadata (token endpoint, JWK Set URI). - -Dauth.jwkSetUri — The URL where the authorization server publishes its public JSON Web Keys. The toolkit fetches these to verify incoming JWT signatures without making a call on every request.
Providing both properties activates OAuth 2.0-based authentication.
Step 2: Test your previous configuration
Before adding authentication, confirm that the HTTPS-only server, from a previous blog post — The Oracle Database MCP Toolkit — HTTP Streamable Mode - still starts cleanly. Open a Windows Command Prompt (CMD) session, navigate to your project directory, and launch the server.
cd C:\oracle-db-mcp-java-toolkit-configs
java -DconfigFile=C:\oracle-db-mcp-java-toolkit-configs\config.yaml -Dtransport=http -Dhttps.port=45450 -DcertificatePath=C:\oracle-db-mcp-java-toolkit-configs\mcp-keystore.p12 -DcertificatePassword=changeit -jar C:\java-projects\mcp\src\oracle-db-mcp-java-toolkit\target\oracle-db-mcp-toolkit-1.0.0.jarPress Ctrl+C to stop it. You are ready to move on to enable OAuth 2.0-based authentication. So, let’s perform the additional configurations as required.
Step 3: Set Up a Local OAuth 2.0 Authorization Server
For development and testing, we will run a minimal OAuth 2.0 authorization server at localhost:9000, and we’ll use the Spring Authorization Server for this purpose.
You can get a Maven project with the complete code sample on GitHub.
Otherwise, using Spring Initializr, create a new project per your preferences, select the required dependencies, then download the project artifact as usual.
Extract the contents of your project, and use your preferred IDE to create a couple of Java classes - AuthServerApplication.java and AuthServerConfig.java.
AuthServerApplication.java
package com.oracle.database.jdbc.oauth2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(AuthServerApplication.class, args);
}
}AuthServerConfig.java
package com.oracle.database.jdbc.oauth2;
import java.util.UUID;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.RequestMatcher;
@Configuration
@EnableWebSecurity
public class AuthServerConfig {
@Bean
@Order(1)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
http.securityMatcher(endpointsMatcher).with(authorizationServerConfigurer, Customizer.withDefaults())
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated()).formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient mcpClient = RegisteredClient.withId(UUID.randomUUID().toString()).clientId("mcp-client")
.clientSecret("{noop}mcp-secret") // {noop} means plain-text password for dev use
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).scope("mcp.access").build();
return new InMemoryRegisteredClientRepository(mcpClient);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer("http://localhost:9000").build();
}
}Create the Application Properties file under src/main/resources as usual:
spring.application.name=oracle-db-mcp-toolkit-oauth2
server.port=9000
spring.security.oauth2.authorizationserver.issuer=http://localhost:9000
spring.security.user.name=user
spring.security.user.password=password
spring.security.oauth2.authorizationserver.client.mcp-client.registration.client-id=mcp-client
spring.security.oauth2.authorizationserver.client.mcp-client.registration.client-secret={noop}mcp-secret
spring.security.oauth2.authorizationserver.client.mcp-client.registration.client-name=MCP Client
spring.security.oauth2.authorizationserver.client.mcp-client.registration.client-authentication-methods=client_secret_basic
spring.security.oauth2.authorizationserver.client.mcp-client.registration.authorization-grant-types=client_credentials
spring.security.oauth2.authorizationserver.client.mcp-client.registration.scopes=mcp.access
Finally, use the Apache Maven tool to build it as usual.
cd C:\java-projects\oracle-db-mcp-toolkit-oauth2
mvn clean package -DskipTestsStart the local authorization service:
cd C:\java-projects\oracle-db-mcp-toolkit-oauth2\target
java -jar oracle-db-mcp-toolkit-oauth2-0.0.1-SNAPSHOT.jarUse this URL to test the endpoint src/main/resources:
Step 4: Verify if the local Authorization Server is up and running
curl http://localhost:9000/.well-known/openid-configurationYou should receive a JSON response containing the issuer, token_endpoint, jwks_uri, and other standard OpenID Connect metadata. Note the values forissuer and jwks_uri as we’ll use them in the next step. They should be like:
- issuer: http://localhost:9000
- jwks_uri: http://localhost:9000/oauth2/jwks
Step 5: Restart the Oracle Database MCP Toolkit with
OAuth 2.0 Authentication Enabled
cd C:\java-projects\mcp\src\oracle-db-mcp-java-toolkit
java "-DconfigFile=C:\oracle-db-mcp-java-toolkit-configs\config.yaml" "-Dtransport=http" "-Dhttps.port=45450" "-DcertificatePath=C:\oracle-db-mcp-java-toolkit-configs\mcp-keystore.p12" "-DcertificatePassword=changeit" "-DenableAuthentication=true" "-DauthServer=http://localhost:9000" "-DintrospectionEndpoint=http://localhost:9000/oauth2/introspect" "-DclientId=mcp-client" "-DclientSecret=mcp-secret" "-DallowedHosts=http://localhost:6274" -jar "C:\java-projects\mcp\src\oracle-db-mcp-java-toolkit\target\oracle-db-mcp-toolkit-1.0.0.jar"Provided that you used the right command as shown above, reflecting your values from the configured local IdP server (from your application.properties file), you will see messages as shown below:
OAuth 2.0 authentication enabled started successfully
Step 6: Test it with an unauthenticated HTTP request
First, confirm the server is now enforcing authentication by sending an unauthenticated HTTP request (without a token):
curl -k -i -v "https://localhost:45450/mcp" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d "{\"jsonrpc\":\"2.0\",\"id\":\"1\",\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"curl-test-client\",\"version\":\"1.0\"}}}"With OAuth 2.0 authentication working as expected, you should now receive:
This confirms the toolkit is rejecting unauthenticated callers.
Step 7: Test it with an authenticated HTTP request (bearer token)
Now that authentication is enabled, every request to the MCP server must include a valid Bearer token. Obtain one from the authorization server using the Client Credentials grant. Open a new Windows CMD session and run the following curl command:
curl -s -X POST http://localhost:9000/oauth2/token -H "Content-Type: application/x-www-form-urlencoded" -u "mcp-client:mcp-secret" -d "grant_type=client_credentials&scope=mcp.access"A successful response looks like this:
Server
Copy the value of access_token. Then, use it to configure an environment variable:
set "ACCESS_TOKEN=YOUR_ACCESS_TOKEN"Note that Bearer tokens are short-lived (typically 5 minutes for the Spring Authorization Server defaults). If your token expires during testing, re-run this command to obtain a fresh one.
Now repeat the request, this time including the Bearer token you configured above.
curl -k -i -v "https://localhost:45450/mcp" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -H "Authorization: Bearer %ACCESS_TOKEN%" --data-raw "{\"jsonrpc\":\"2.0\",\"id\":\"1\",\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"mcp-client\",\"version\":\"1.0\"}}}"A successful response returns HTTP 200, but is now gated by OAuth 2.0 authentication.
Your Oracle Database MCP Toolkit is now running over HTTPS with OAuth 2.0 authentication enforced. Only callers with a valid Bearer token issued by your trusted authorization server can reach the database tools.
Wrapping it up
That’s it! An OAuth 2.0-based authentication approach scales cleanly from development to production.
We used Spring for learning purposes on this blog. However, concerning a production deployment, replace the local Spring Authorization Server with your preferred identity provider, such as OCI Identity and Access Management.
I hope you found this blog post useful. Thanks for reading!
Frequently Asked Questions (FAQs)
What is the difference between TLS and OAuth 2.0 authentication in
this context?
TLS (configured via the PKCS12 keystore in a previous blog post) encrypts the communication channel. It protects data in transit against eavesdropping and tampering, but it says nothing about who is allowed to call the server. OAuth 2.0 authentication controls access — it ensures that only clients presenting a valid token from a trusted authorization server can invoke MCP tools. Both layers are necessary for a secure deployment.
Can I use OCI IAM as the authorization server instead
of the local Spring Authorization Server?
Yes, and that is the recommended approach for any shared or production environment. The token acquisition step changes to call the OCI AIM token endpoint with the client ID and secret registered in that identity domain.
How do I customize what the toolkit can do without changing code?
You define data sources and tools in a YAML config file. The server reads this on startup, registers built-in tools, and also exposes any custom SQL-backed tools you define in that configuration.
What happens if the Bearer token expires mid-session?
The toolkit validates the token on every incoming request. Once the token’s exp claim is in the past, the server returns HTTP 401. The MCP client must then obtain a fresh token from the authorization server and retry the request. For long-running sessions, implement a token-refresh loop in your client before the token expires.
References
- MCP — Model Context Protocol
- Oracle Database MCP Toolkit
- OAuth 2.0
- Spring Authorization Server
- Spring Boot 4
- Oracle Cloud Infrastructure Identity and Access Management (IAM) — Product Page
- Oracle Cloud Infrastructure Identity and Access Management (IAM) — Documentation
- Oracle MCP Server Repository
- Oracle AI Database 26ai
- Oracle AI Database 26ai Free Container Image
- Oracle JDBC Driver
- Oracle® AI Database JDBC Java API Reference, Release 26ai
- Oracle® AI Database Universal Connection Pool Java API Reference, Release 26ai
- Database Navigator — JetBrains Marketplace
- Quickstart: Connect to Oracle Database using IntelliJ IDEA
- Developers Guide For Oracle JDBC on Maven Central
- Develop Java applications with Oracle Database
Oracle Developers and Oracle OCI Free Tier
Join our Oracle Developers channel on Slack to discuss Java, GenAI, Agentic AI, JDK, JDBC, GraalVM, Micronaut, Spring Boot, Helidon, Quarkus, Reactive Streams, Cloud, DevOps, SRE, IaC, and other topics!
Build, test, and deploy your applications on Oracle Cloud — for free! Get access to OCI Cloud Free Tier!
