Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Copilot Instructions for auth0-java-mvc-common

## Overview

This is an Auth0 SDK for Java Servlet applications that simplifies OAuth2/OpenID Connect authentication flows. The library provides secure cookie-based state/nonce management and handles both Authorization Code and Implicit Grant flows.

## Core Architecture

### Main Components

- **`AuthenticationController`**: Primary entry point with Builder pattern for configuration
- **`RequestProcessor`**: Internal handler for OAuth callbacks and token processing
- **`AuthorizeUrl`**: Fluent builder for constructing OAuth authorization URLs
- **Cookie Management**: Custom `AuthCookie`/`TransientCookieStore` for SameSite cookie support

### Key Design Patterns

- **Non-reusable builders**: `AuthenticationController.Builder` throws `IllegalStateException` if `build()` called twice
- **One-time URL builders**: `AuthorizeUrl` instances cannot be reused (throws on second `build()`)
- **Fallback authentication storage**: State/nonce stored in both cookies AND session for compatibility

## Critical Cookie Handling

The library implements sophisticated cookie management for browser compatibility:

### SameSite Cookie Strategy

- **Code flow**: Uses `SameSite=Lax` (single cookie)
- **ID token flows**: Uses `SameSite=None; Secure` with legacy fallback cookie (prefixed with `_`)
- **Legacy fallback**: Automatically creates fallback cookies for browsers that don't support `SameSite=None`

### Cookie Configuration

```java
// Configure cookie behavior
.withLegacySameSiteCookie(false) // Disable fallback cookies
.withSecureCookie(true) // Force Secure attribute
.withCookiePath("/custom") // Set cookie Path attribute
```

## Builder Pattern Usage

### Standard Authentication Controller Setup

```java
AuthenticationController controller = AuthenticationController.newBuilder(domain, clientId, clientSecret)
.withJwkProvider(jwkProvider) // Required for RS256
.withResponseType("code") // Default: "code"
.withClockSkew(120) // Default: 60 seconds
.withOrganization("org_id") // For organization login
.build();
```

### URL Building (Modern Pattern)

```java
// CORRECT: Use request + response for cookie storage
String url = controller.buildAuthorizeUrl(request, response, redirectUri)
.withState("custom-state")
.withAudience("https://api.example.com")
.withParameter("custom", "value")
.build();
```

## Response Type Behavior

- **`code`**: Authorization Code flow, uses `SameSite=Lax` cookies
- **`id_token`** or **`token`**: Implicit Grant, requires `SameSite=None; Secure` + fallback cookies
- **Mixed**: `id_token code` combinations follow implicit grant cookie rules

## Testing Patterns

### Mock Setup

```java
// Standard test setup pattern
@Mock private AuthAPI client;
@Mock private IdTokenVerifier.Options verificationOptions;
@Captor private ArgumentCaptor<SignatureVerifier> signatureVerifierCaptor;

AuthenticationController.Builder builderSpy = spy(AuthenticationController.newBuilder(...));
doReturn(client).when(builderSpy).createAPIClient(...);
```

### Cookie Assertions

```java
// Verify cookie headers in tests
List<String> headers = response.getHeaders("Set-Cookie");
assertThat(headers, hasItem("com.auth0.state=value; HttpOnly; Max-Age=600; SameSite=Lax"));
```

## Development Workflow

### Build & Test

```bash
./gradlew build # Build with Gradle wrapper
./gradlew test # Run tests
./gradlew jacocoTestReport # Generate coverage
```

### Key Dependencies

- **Auth0 Java SDK**: Core Auth0 API client (`com.auth0:auth0`)
- **java-jwt**: JWT token handling (`com.auth0:java-jwt`)
- **jwks-rsa**: RS256 signature verification (`com.auth0:jwks-rsa`)
- **Servlet API**: `javax.servlet-api` (compile-only)

## Migration Considerations

### Deprecated Methods

- `handle(HttpServletRequest)`: Session-based, incompatible with SameSite restrictions
- `buildAuthorizeUrl(HttpServletRequest, String)`: Session-only storage

### Modern Alternatives

- Use `handle(HttpServletRequest, HttpServletResponse)` for cookie-based auth
- Use `buildAuthorizeUrl(HttpServletRequest, HttpServletResponse, String)` for proper cookie storage

## Common Integration Points

- Organizations: Use `.withOrganization()` and validate `org_id` claims manually
- Custom parameters: Use `.withParameter()` on AuthorizeUrl (but not for `state`, `nonce`, `response_type`)
- Error handling: Catch `IdentityVerificationException` from `.handle()` calls
- HTTP customization: Use `.withHttpOptions()` for timeouts/proxy configuration
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM gradle:6.9.2-jdk8

WORKDIR /home/gradle
# Copy your project files
COPY . .

# Ensure the Gradle wrapper is executable
RUN chmod +x ./gradlew

# Expose both ports for your MCD test
EXPOSE 3000
EXPOSE 8080
EXPOSE 5005

# Use --no-daemon to keep the container process alive
# We use the wrapper (./gradlew) to ensure consistency
#CMD ["./gradlew", "appRun", "--no-daemon", "-Pgretty.managed=false"]
ENV GRADLE_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
CMD ["gradle", "appRun", "--no-daemon"]
10 changes: 10 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ plugins {
id 'jacoco'
id 'me.champeau.gradle.japicmp' version '0.4.6'
id 'io.github.gradle-nexus.publish-plugin' version '2.0.0'
id "war"
id "org.gretty" version "3.1.1"
}

gretty {
httpPort = 3000
host = '0.0.0.0' // Required for Docker to communicate
contextPath = '/'
servletContainer = 'tomcat9'
}

repositories {
Expand Down Expand Up @@ -125,6 +134,7 @@ dependencies {
implementation 'org.apache.commons:commons-lang3:3.18.0'
implementation 'com.google.guava:guava-annotations:r03'
implementation 'commons-codec:commons-codec:1.20.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'

api 'com.auth0:auth0:1.45.1'
api 'com.auth0:java-jwt:3.19.4'
Expand Down
Loading
Loading