1. OAuth Server Module
The quantum-oauth-server is an optional module that turns any Quantum application into a standalone OAuth 2.0 / OIDC authorization server. When added, your application exposes standard OAuth endpoints (/oauth/authorize, /oauth/token, /oauth/jwks, /.well-known/openid-configuration, /oauth/userinfo) so external clients can authenticate using industry-standard OAuth flows — without requiring an external identity provider like Keycloak, Cognito, Auth0, or Okta.
This is the complement to the OIDC/Cognito provider modules: those modules let Quantum consume tokens from an external IdP, while this module lets Quantum issue tokens itself.
1.1. When to Use
Use quantum-oauth-server when:
-
You want ChatGPT, Gemini, Grok, or other AI platforms to connect to your MCP server via OAuth
-
Third-party applications need OAuth-based access to your APIs
-
You want a self-contained deployment with no external IdP dependency
-
You already manage user identities in Quantum (credentials, user profiles, user groups) and want to leverage them directly
Use an external IdP (Cognito, Keycloak, Auth0) instead when:
-
You need advanced IdP features (social login, MFA, federation, SAML)
-
Your organization already standardizes on a specific IdP
-
You need to share identities across non-Quantum applications
1.2. Adding the Dependency
<dependency>
<groupId>com.end2endlogic</groupId>
<artifactId>quantum-oauth-server</artifactId>
</dependency>
The OAuth endpoints activate automatically via CDI discovery. No additional configuration is needed beyond the standard JWT properties that your application already has.
1.3. Prerequisites
The module delegates to existing Quantum infrastructure. Ensure your application has:
# These properties are already configured if you use quantum-jwt-provider
mp.jwt.verify.issuer=https://your-app.example.com
mp.jwt.verify.publickey.location=publicKey.pem
auth.jwt.secret=${JWT_SECRET}
com.b2bi.jwt.duration=3600
1.4. Endpoints
| Endpoint | Method | Auth | Description |
|---|---|---|---|
|
GET |
Public |
OIDC discovery document. Returns issuer, endpoint URLs, supported grant types, signing algorithms, and scopes. OAuth clients use this for auto-configuration. |
|
GET |
Public |
JSON Web Key Set. Serves the RSA public key (from |
|
GET |
Public |
Authorization endpoint. Validates the client and request parameters, then presents a login form to the user. Supports PKCE with S256 code challenge method. |
|
POST |
Public |
Processes the login form submission. Authenticates the user via |
|
POST |
Public |
Token endpoint. Exchanges credentials or codes for access and refresh tokens. Supports |
|
GET |
Bearer |
Returns claims about the authenticated user ( |
1.5. Supported Grant Types
Authorization Code + PKCE
The primary flow for browser-based OAuth clients (ChatGPT, Gemini, Grok, web applications).
1. Client redirects user to:
GET /oauth/authorize?response_type=code
&client_id=my-client
&redirect_uri=https://client.example.com/callback
&scope=openid+profile+email
&state=random-state
&code_challenge=BASE64URL(SHA256(code_verifier))
&code_challenge_method=S256
2. User sees login form, enters credentials
3. Server authenticates user, generates authorization code,
redirects to:
https://client.example.com/callback?code=XXXXX&state=random-state
4. Client exchanges code for tokens:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=XXXXX
&redirect_uri=https://client.example.com/callback
&client_id=my-client
&client_secret=my-secret
&code_verifier=original-random-verifier
5. Server returns:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJ..."
}
Client Credentials
For service-to-service integrations where no user interaction is needed.
POST /oauth/token
Authorization: Basic BASE64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
Response:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600
}
For client_credentials, the server looks up a CredentialUserIdPassword with a userId matching the client_id. Create this credential when registering the client.
Refresh Token
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=eyJ...
&client_id=my-client
&client_secret=my-secret
1.6. Registering OAuth Clients
An OAuthClient document must exist in the oauth_clients MongoDB collection before a client can authenticate. Create one via the Quantum API, seed packs, or directly in MongoDB.
| Field | Type | Description |
|---|---|---|
|
String |
Unique client identifier (e.g., |
|
String |
Bcrypt hash of the client secret. Use |
|
boolean |
If |
|
List<String> |
Allowed redirect URIs. The authorization endpoint rejects requests with unregistered URIs. |
|
List<String> |
Allowed grant types: |
|
List<String> |
Allowed scopes (e.g., |
|
String |
The realm this client is associated with for tenant scoping. |
|
boolean |
Set to |
For client_credentials grant, also create a CredentialUserIdPassword with userId matching the clientId and credentialType=OAUTH:
CredentialUserIdPassword cred = CredentialUserIdPassword.builder()
.userId("chatgpt-mcp-client")
.subject(UUID.randomUUID().toString())
.credentialType(CredentialType.OAUTH)
.roles(new String[]{"user"})
.domainContext(domainContext)
.lastUpdate(new Date())
.build();
1.7. Integration Examples
ChatGPT MCP Integration
Register your Quantum MCP server in ChatGPT with these settings:
| ChatGPT Field | Value |
|---|---|
Server URL |
|
Authentication |
OAuth 2.0 |
Authorization URL |
|
Token URL |
|
Client ID |
Your registered |
Client Secret |
The plaintext secret (hashed version stored in |
Scopes |
|
When a user connects via ChatGPT:
-
ChatGPT opens a browser to
/oauth/authorizewith the registered client_id -
The user sees the Quantum login form and enters their credentials
-
On success, the server redirects back to ChatGPT with an authorization code
-
ChatGPT exchanges the code for tokens at
/oauth/token -
Subsequent MCP tool calls include the access token as a Bearer header
-
Quantum’s
SecurityFiltervalidates the token (same issuer, same keys) and establishes the user’s security context
Gemini / Grok / Other AI Platforms
The same pattern applies to any AI platform that supports OAuth 2.0:
-
Register an
OAuthClientwith the platform’s callback URL as a redirect URI -
Provide the discovery URL (
/.well-known/openid-configuration) or the individual endpoint URLs -
The platform handles the OAuth flow; Quantum handles authentication and token issuance
Service-to-Service (Client Credentials)
For backend integrations that don’t involve user interaction:
# Obtain an access token
TOKEN=$(curl -s -X POST https://your-app.example.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=my-service" \
-d "client_secret=my-secret" | jq -r '.access_token')
# Use the token to call APIs
curl -H "Authorization: Bearer $TOKEN" https://your-app.example.com/api/...
1.8. Architecture
The module is a thin REST layer over existing Quantum infrastructure:
| Existing Component | OAuth Use |
|---|---|
|
Issues access tokens at |
|
Issues refresh tokens |
|
Serves the |
|
Validates user credentials during authorization code flow |
|
Looks up user and client credentials |
RSA key pair ( |
Signs all issued tokens |
|
Populates the discovery document |
|
Validates the issued tokens on subsequent API calls (same issuer, same keys) |
Tokens issued by the OAuth server are standard Quantum JWTs — indistinguishable from tokens issued via /security/login or /auth/login. Any Quantum endpoint that accepts a Bearer token will accept tokens from the OAuth server.
1.9. Data Model
Two new MongoDB collections are created:
-
oauth_clients— registered OAuth clients (persistent, managed by admin) -
oauth_authorization_codes— short-lived authorization codes (auto-expire after 5 minutes via MongoDB TTL index)
Both follow standard Quantum patterns (BaseModel, realm-scoped, Morphia-managed).
1.10. Security Considerations
-
Store client secrets securely. The
clientSecretHashuses bcrypt — never store plaintext secrets. -
Use HTTPS for all OAuth endpoints in production.
-
Register specific
redirectUrisper client — never use wildcards. -
PKCE (S256) is supported and recommended for all authorization code flows.
-
Authorization codes are single-use and expire after 5 minutes.
-
For public clients (SPAs), set
publicClient=trueand rely on PKCE for security. -
The login form is minimal by design. For custom branding, override
OAuthAuthorizeResourcein your application.