Skip to content

[FEATURE]Backend Proxy for OAuth/OIDC Configuration Access #1665

Description

@prasadtalasila

Description

Implement a backend proxy layer to handle OAuth/OIDC discovery endpoint requests from the DTaaS frontend. This resolves Chrome's CORS policy and Private Network Access restrictions that currently block direct access to the GitLab OAuth server from the browser.

Problem Statement

The DTaaS frontend (intocps.org) cannot directly access GitLab's OAuth/OIDC endpoint (dtaas.com/gitlab/.well-known/openid-configuration) due to browser security restrictions:

  1. Chrome CORS Blocking: Direct requests from the public frontend to the private GitLab server are blocked with:

    Access to fetch at 'https://dtaas.com/gitlab/.well-known/openid-configuration' 
    from origin 'https://intocps.org' has been blocked by CORS policy: 
    Permission was denied for this request to access the `local` address space.
    
  2. Private Network Access Restriction: Chrome enforces Private Network Access (RFC 1918) restrictions, preventing public origins from accessing private/local network addresses, even with proper CORS headers.

  3. Impact: OAuth/OIDC login flow fails at the initial discovery phase, preventing user authentication.

  4. Environment: This issue occurs in both development and production environments where the frontend is on a public domain and GitLab OAuth server is on a private network.

Current Behavior

Frontend (Public) 
    ↓ [BLOCKED]
GitLab OAuth Server (Private Network)

Browser console errors:

  • Access to fetch blocked by CORS policy
  • Failed to load resource: net::ERR_FAILED
  • net::ERR_BLOCKED_BY_CLIENT

Proposed Solution

Implement a backend proxy layer that routes OAuth/OIDC discovery requests through the public DTaaS API, allowing the browser to communicate with a same-origin endpoint while the backend handles private network access.

Architecture

Frontend (Public: intocps.org)
    ↓
Backend API Gateway (intocps.org/api/oauth/...)
    ↓ [Private Network Access - No Browser Restrictions]
GitLab OAuth Server (dtaas.com)

Implementation Details

1. Backend Endpoint

Add a new endpoint to the DTaaS backend API (Python/FastAPI or equivalent):

# Example: backend/dtaas/api/oauth.py
@router.get("/oauth/openid-config")
async def get_openid_configuration():
    """
    Proxy for GitLab's .well-known/openid-configuration
    Allows frontend to access OAuth discovery without CORS/Private Network Access blocking
    """
    gitlab_oauth_url = os.getenv("GITLAB_OAUTH_SERVER")
    config_url = f"{gitlab_oauth_url}/gitlab/.well-known/openid-configuration"
    
    async with httpx.AsyncClient() as client:
        response = await client.get(config_url)
        response.raise_for_status()
    
    return response.json()

@router.post("/oauth/token")
async def exchange_code_for_token(request: OAuthTokenRequest):
    """
    Exchange authorization code for access token
    """
    gitlab_oauth_url = os.getenv("GITLAB_OAUTH_SERVER")
    token_url = f"{gitlab_oauth_url}/oauth/token"
    
    payload = {
        "client_id": os.getenv("GITLAB_OAUTH_CLIENT_ID"),
        "client_secret": os.getenv("GITLAB_OAUTH_CLIENT_SECRET"),
        "code": request.code,
        "grant_type": "authorization_code",
        "redirect_uri": request.redirect_uri,
    }
    
    async with httpx.AsyncClient() as client:
        response = await client.post(token_url, data=payload)
        response.raise_for_status()
    
    return response.json()

2. Environment Configuration

Add to deployment configuration:

GITLAB_OAUTH_SERVER=https://dtaas.com
GITLAB_OAUTH_CLIENT_ID=<client_id>
GITLAB_OAUTH_CLIENT_SECRET=<client_secret>
OAUTH_REDIRECT_URI=https://intocps.org/_oauth

3. Frontend Changes

Update OAuth discovery logic to use backend proxy:

// Before (Direct - Blocked)
const response = await fetch(
  'https://dtaas.com/gitlab/.well-known/openid-configuration'
);

// After (Via Backend Proxy)
const response = await fetch(
  'https://intocps.org/api/oauth/openid-config'
);

Benefits

  • ✅ Resolves Chrome CORS and Private Network Access blocking
  • ✅ Credentials kept on backend (not exposed to browser)
  • ✅ Works consistently across all browsers and environments
  • ✅ Production-ready security posture
  • ✅ Maintainable and scalable architecture
  • ✅ No need for browser configuration changes or flags

Alternative Solution 1: Nginx Proxy Headers

Configure the GitLab/OAuth server's reverse proxy to add CORS headers. Note: This alone does NOT bypass Private Network Access restrictions.

Nginx Configuration

Add to the OAuth server's nginx configuration:

location /gitlab/.well-known/openid-configuration {
    add_header 'Access-Control-Allow-Origin' 'https://intocps.org' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
    
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Max-Age' '86400';
        return 204;
    }
    
    proxy_pass http://gitlab_backend;
}

location /oauth/authorize {
    add_header 'Access-Control-Allow-Origin' 'https://intocps.org' always;
    proxy_pass http://gitlab_backend;
}

location /oauth/token {
    add_header 'Access-Control-Allow-Origin' 'https://intocps.org' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    proxy_pass http://gitlab_backend;
}

Limitations

  • ⚠️ Does NOT resolve Private Network Access blocking — Chrome still blocks requests from public origins to private addresses regardless of CORS headers
  • ⚠️ Requires access to OAuth server's nginx configuration
  • ⚠️ Only suitable for development environments with flagged Chrome instances
  • ✅ Useful as a supplementary measure to ensure proper CORS headers are present

Alternative Solution 2: DNS and Certificate

Register the GitLab OAuth server with a valid public DNS entry and trusted SSL certificate, so Chrome no longer treats it as a "local" address.

Limitations

  • ⚠️ Requires public DNS registration and SSL certification
  • ⚠️ Exposes internal infrastructure to the public internet
  • ⚠️ Significant security and operational overhead
  • ⚠️ Not practical for private/internal deployments

Implementation Scope

Phase 1: Core Proxy (Priority)

  • Implement backend proxy endpoints for OAuth discovery
  • Implement token exchange endpoint
  • Add environment variable configuration
  • Update frontend to use proxy endpoints
  • Add unit/integration tests
  • Update API documentation

Phase 2: Enhanced Security (Optional)

  • Add rate limiting to OAuth endpoints
  • Implement request validation
  • Add logging and monitoring
  • Add CSRF protection for token exchange

Phase 3: Nginx Configuration (Optional)

  • Document recommended nginx headers as best practice
  • Update deployment guides

Testing Strategy

Manual Testing

  1. Deploy with backend proxy enabled
  2. Verify frontend can access OAuth discovery endpoint at GET /api/oauth/openid-config
  3. Verify OAuth login flow completes without CORS errors
  4. Test in both Chrome and other browsers
  5. Verify credentials are not logged or exposed

Automated Testing

  • Unit tests for proxy endpoints
  • Integration tests for OAuth flow
  • Browser automation tests (Selenium/Playwright) for end-to-end flow

Related Issues & Documentation

Additional Context

This feature addresses a fundamental architectural limitation in the current OAuth setup and is essential for:

  • Reliable user authentication in production
  • Multi-user deployments with centralized identity management
  • Compliance with modern browser security standards
  • Long-term maintainability of the authentication system

The backend proxy pattern is industry-standard and recommended by OWASP and OAuth 2.0 specifications for browser-based applications accessing protected resources.


Would this solution require user passing OIDC credentials to proxy?

No, absolutely not. This is actually one of the security benefits of the backend proxy approach.

Here's the OAuth 2.0 Authorization Code flow breakdown:

Flow: Where Credentials Go

1. User clicks "Login"
   ↓
2. Frontend → GitLab's /oauth/authorize endpoint
   (User enters credentials directly on GitLab's server)
   ↓
3. User authorizes app on GitLab
   ↓
4. GitLab redirects back to Frontend with authorization CODE
   ↓
5. Frontend → Backend Proxy with CODE
   ↓
6. Backend Proxy + Backend Secret → GitLab's /oauth/token endpoint
   (Exchange code for access token)
   ↓
7. Backend returns token to Frontend

What Users Pass To The Proxy

Authorization code only — This is a single-use, short-lived code (expires in minutes)
Not sensitive — Code is worthless without the client_secret

What Users Never Pass To Proxy

Username/Password — Entered directly on GitLab's server, never sent to proxy
OIDC tokens — Backend handles token exchange, frontend gets the final access token
Client secret — Stays on backend only

Security Advantage

The backend proxy actually improves security because:

  1. Client secret stays on backend — Never exposed to browser or user
  2. User credentials never touch the proxy — Only GitLab authentication server sees them
  3. Token exchange happens server-to-server — No browser involvement in sensitive operations
  4. Credentials not logged in browser — Unlike if frontend did direct token exchange

In contrast, if your frontend were doing direct token exchange with credentials, that would be a red flag. But the Authorization Code flow with backend proxy is the OAuth 2.0 recommended pattern — it's what Google, GitHub, and every major platform does.

So you're good on the security front! 🔒

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions