Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 25, 2025

Enables testing of authentication failure flows by allowing the mock OAuth2 server to return error responses instead of auto-approving all authorization requests.

Changes

API

  • /config endpoint now accepts error_scenario object with enabled, endpoint, error, and error_description fields
  • When enabled for the authorize endpoint, returns error redirect instead of authorization code

Error Types
Added support for all OAuth 2.0 RFC 6749 error codes:

  • access_denied, invalid_request, unauthorized_client
  • unsupported_response_type, invalid_scope
  • server_error, temporarily_unavailable

Implementation

  • Modified AuthorizeHandler to check for configured error scenarios before generating auth codes
  • Extended ErrorScenario type with Enabled field to toggle scenarios on/off
  • Updated MemoryStore.GetErrorScenario() to only return enabled scenarios

Example Usage

# Configure error scenario
POST /config
{
  "error_scenario": {
    "enabled": true,
    "endpoint": "authorize",
    "error": "access_denied",
    "error_description": "User denied access"
  }
}

# Authorization request now returns:
# GET /authorize?client_id=...&redirect_uri=http://app/callback
# → 302 http://app/callback?error=access_denied&error_description=User+denied+access&state=...

Set enabled: false to restore auto-approval behavior.

Original prompt

This section details on the original issue you should resolve

<issue_title>[FEATURE] Implement error scenarios</issue_title>
<issue_description># Mock OAuth Error Scenarios - Feature Request

Problem

I have a project that uses the Goloang Mock Oauth2 server for testing. In this project I have a test "should redirect to login when accessing dashboard without authentication" which is currently skipped because the mock OAuth server auto-authenticates all requests, making it impossible to test unauthenticated access scenarios.

Current Behavior

When a test tries to access a page that requires authentication without cookies in a fresh browser context:

  1. Test navigates to page requiring authentication
  2. Test server redirects to /auth/login
  3. Auth service redirects to mock OAuth /authorize
  4. Mock OAuth auto-approves and redirects back with auth code
  5. User ends up authenticated on page requiring authentication

This auto-approval behavior is great for testing happy paths, but prevents testing authentication failure scenarios.

Proposed Solution

Add an error_scenario configuration option to the mock OAuth server that allows tests to simulate authentication failures or rejections.

API Design

Endpoint: POST http://localhost:9090/config

Request Body:

{
  "error_scenario": {
    "enabled": true,
    "error": "access_denied",
    "error_description": "User denied access"
  }
}

Supported Error Types

Following OAuth 2.0 spec (RFC 6749):

  1. access_denied - User or authorization server denied the request

    {
      "error": "access_denied",
      "error_description": "User denied access"
    }
  2. invalid_request - Request missing required parameter

    {
      "error": "invalid_request",
      "error_description": "Missing client_id parameter"
    }
  3. unauthorized_client - Client not authorized to use this method

    {
      "error": "unauthorized_client",
      "error_description": "Client not authorized"
    }
  4. unsupported_response_type - Server doesn't support obtaining auth code

    {
      "error": "unsupported_response_type",
      "error_description": "Response type not supported"
    }
  5. invalid_scope - Requested scope invalid or unknown

    {
      "error": "invalid_scope",
      "error_description": "Scope 'admin' is not available"
    }
  6. server_error - Server encountered unexpected error

    {
      "error": "server_error",
      "error_description": "Internal server error"
    }
  7. temporarily_unavailable - Server temporarily unavailable

    {
      "error": "temporarily_unavailable",
      "error_description": "Server is under maintenance"
    }

Behavior

When error_scenario.enabled = true:

  • /authorize endpoint: Returns error redirect to callback URL with error parameters

    http://localhost:8080/auth/callback?error=access_denied&error_description=User+denied+access&state=<state>
    
  • /token endpoint: Returns HTTP 400 with error JSON

    {
      "error": "invalid_grant",
      "error_description": "Authorization code is invalid"
    }

When error_scenario.enabled = false (default):

  • Normal auto-approval behavior (current functionality)

Disabling Error Scenario

Reset to normal behavior:

{
  "error_scenario": {
    "enabled": false
  }
}

Test Implementation

Updated Test

test('should redirect to login when accessing dashboard without authentication', async ({ page }) => {
  // Create a completely new browser context with no cookies
  const context = await page.context().browser().newContext();
  const newPage = await context.newPage();
  
  // Configure mock OAuth to reject authentication attempts
  await fetch('http://localhost:9090/config', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      error_scenario: {
        enabled: true,
        error: 'access_denied',
        error_description: 'User denied access'
      }
    })
  });
  
  // Try to access page requiring authentication directly
  await newPage.goto('/dashboard');
  await newPage.waitForLoadState('networkidle');
  
  const currentUrl = newPage.url();
  
  // Should be redirected to /auth/login (unauthenticated)
  // OR back to home page with error
  expect(currentUrl).toMatch(/\/(auth\/login|error|$)/);
  
  // Reset mock OAuth for other tests
  await fetch('http://localhost:9090/config', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      error_scenario: { enabled: false }
    })
  });
  
  await context.close();
});

Test Isolation

Use test.beforeEach and test.afterEach to ensure error scenarios don't leak:

test.describe('Authentication Error Scenarios', () => {
  test.afterEach(asy...

</details>

- Fixes chrisw-dev/golang-mock-oauth2-server#9

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for you](https://github.com/chrisw-dev/golang-mock-oauth2-server/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)  coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Implement error scenarios for OAuth testing Add configurable error scenarios for /authorize endpoint Oct 25, 2025
Copilot AI requested a review from chrisw-dev October 25, 2025 13:43
Copilot finished work on behalf of chrisw-dev October 25, 2025 13:43
@chrisw-dev chrisw-dev marked this pull request as ready for review October 25, 2025 13:47
@chrisw-dev chrisw-dev merged commit b79a42e into main Oct 25, 2025
1 check passed
@chrisw-dev chrisw-dev deleted the copilot/implement-error-scenarios branch October 25, 2025 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants