# OAuth 2.1 Quick Start Examples

## PKCE Code Generation (Shell Script)

```bash
# Generate code verifier
CODE_VERIFIER=$(openssl rand -base64 32 | tr -d '+/' | tr '=' '_' | cut -c1-43)

# Generate code challenge
CODE_CHALLENGE=$(echo -n "$CODE_VERIFIER" | openssl dgst -binary -sha256 | openssl base64 | tr -d '+/' | tr '=' '_')

echo "Code Verifier: $CODE_VERIFIER"
echo "Code Challenge: $CODE_CHALLENGE"
```

## PKCE Code Generation (Python)

```python
import base64
import hashlib
import os

# Generate code verifier
code_verifier = base64.urlsafe_b64encode(os.urandom(32)).decode('utf-8').rstrip('=')

# Generate code challenge
code_challenge = base64.urlsafe_b64encode(
    hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')

print(f"Code Verifier: {code_verifier}")
print(f"Code Challenge: {code_challenge}")
```

## PKCE Code Generation (JavaScript/Node.js)

```javascript
const crypto = require('crypto');

// Generate code verifier
const codeVerifier = base64URLEncode(crypto.randomBytes(32));

// Generate code challenge
const hash = crypto.createHash('sha256').update(codeVerifier).digest();
const codeChallenge = base64URLEncode(hash);

function base64URLEncode(str) {
    return str.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}

console.log('Code Verifier:', codeVerifier);
console.log('Code Challenge:', codeChallenge);
```

## Complete Authorization Code Flow Example

### Step 1: Start Authorization

```bash
# Generate PKCE
CODE_VERIFIER=$(openssl rand -base64 32 | tr -d '+/' | tr '=' '_' | cut -c1-43)
CODE_CHALLENGE=$(echo -n "$CODE_VERIFIER" | openssl dgst -binary -sha256 | openssl base64 | tr -d '+/' | tr '=' '_')

# Open in browser
open "http://localhost:9000/oauth2/authorize?response_type=code&client_id=public-client&redirect_uri=http://127.0.0.1:8080/authorized&scope=openid%20profile%20email%20read%20write&code_challenge=$CODE_CHALLENGE&code_challenge_method=S256&state=xyz123"
```

### Step 2: Get Tokens

```bash
# After login and approval, extract the code from redirect URL
# Then exchange it for tokens

curl -X POST http://localhost:9000/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=YOUR_AUTHORIZATION_CODE" \
  -d "redirect_uri=http://127.0.0.1:8080/authorized" \
  -d "client_id=public-client" \
  -d "code_verifier=$CODE_VERIFIER"
```

### Step 3: Use Access Token

```bash
# Get user info
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  http://localhost:9000/userinfo
```

### Step 4: Refresh Token

```bash
curl -X POST http://localhost:9000/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=YOUR_REFRESH_TOKEN" \
  -d "client_id=public-client"
```

## Client Credentials Flow (Server-to-Server)

```bash
curl -X POST http://localhost:9000/oauth2/token \
  -u confidential-client:secret \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "scope=read write"
```

## Inspect JWT Token

```bash
# Copy your access token and decode at jwt.io
# Or use command line:

echo "YOUR_JWT_TOKEN" | cut -d. -f2 | base64 -d | jq '.'
```

## Test with cURL

### Get Well-Known Configuration

```bash
curl http://localhost:9000/.well-known/oauth-authorization-server | jq '.'
```

### Get JWK Set

```bash
curl http://localhost:9000/oauth2/jwks | jq '.'
```

### Token Introspection

```bash
curl -X POST http://localhost:9000/oauth2/introspect \
  -u confidential-client:secret \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=YOUR_ACCESS_TOKEN"
```

### Token Revocation

```bash
curl -X POST http://localhost:9000/oauth2/revoke \
  -u confidential-client:secret \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=YOUR_ACCESS_TOKEN"
```

## Integration Examples

### Spring Boot Resource Server

```yaml
# application.yml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:9000
```

```java
@Configuration
@EnableWebSecurity
public class ResourceServerConfig {
    
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(Customizer.withDefaults())
            );
        return http.build();
    }
}
```

### React SPA with PKCE

```javascript
// OAuth client configuration
const config = {
    authorizationEndpoint: 'http://localhost:9000/oauth2/authorize',
    tokenEndpoint: 'http://localhost:9000/oauth2/token',
    clientId: 'public-client',
    redirectUri: 'http://localhost:3000/callback',
    scope: 'openid profile email read write'
};

// Generate PKCE
async function generatePKCE() {
    const verifier = generateRandomString(43);
    const challenge = await pkceChallengeFromVerifier(verifier);
    sessionStorage.setItem('code_verifier', verifier);
    return challenge;
}

function generateRandomString(length) {
    const array = new Uint8Array(length);
    crypto.getRandomValues(array);
    return base64URLEncode(array);
}

async function pkceChallengeFromVerifier(verifier) {
    const encoder = new TextEncoder();
    const data = encoder.encode(verifier);
    const hash = await crypto.subtle.digest('SHA-256', data);
    return base64URLEncode(new Uint8Array(hash));
}

function base64URLEncode(buffer) {
    return btoa(String.fromCharCode(...buffer))
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}

// Start OAuth flow
async function login() {
    const codeChallenge = await generatePKCE();
    const state = generateRandomString(20);
    sessionStorage.setItem('oauth_state', state);
    
    const params = new URLSearchParams({
        response_type: 'code',
        client_id: config.clientId,
        redirect_uri: config.redirectUri,
        scope: config.scope,
        code_challenge: codeChallenge,
        code_challenge_method: 'S256',
        state: state
    });
    
    window.location.href = `${config.authorizationEndpoint}?${params}`;
}

// Handle callback
async function handleCallback() {
    const params = new URLSearchParams(window.location.search);
    const code = params.get('code');
    const state = params.get('state');
    
    if (state !== sessionStorage.getItem('oauth_state')) {
        throw new Error('Invalid state parameter');
    }
    
    const codeVerifier = sessionStorage.getItem('code_verifier');
    
    const tokenResponse = await fetch(config.tokenEndpoint, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: new URLSearchParams({
            grant_type: 'authorization_code',
            code: code,
            redirect_uri: config.redirectUri,
            client_id: config.clientId,
            code_verifier: codeVerifier
        })
    });
    
    const tokens = await tokenResponse.json();
    sessionStorage.setItem('access_token', tokens.access_token);
    sessionStorage.setItem('refresh_token', tokens.refresh_token);
    
    return tokens;
}
```

### Android/Kotlin Example

```kotlin
// Using AppAuth library
val config = AuthorizationServiceConfiguration(
    Uri.parse("http://localhost:9000/oauth2/authorize"),
    Uri.parse("http://localhost:9000/oauth2/token")
)

val request = AuthorizationRequest.Builder(
    config,
    "public-client",
    ResponseTypeValues.CODE,
    Uri.parse("myapp://callback")
)
    .setScope("openid profile email read write")
    .setCodeVerifier(CodeVerifierUtil.generateRandomCodeVerifier())
    .build()

val authService = AuthorizationService(context)
val authIntent = authService.getAuthorizationRequestIntent(request)
startActivityForResult(authIntent, AUTH_REQUEST_CODE)
```

### iOS/Swift Example

```swift
// Using AppAuth library
let config = OIDServiceConfiguration(
    authorizationEndpoint: URL(string: "http://localhost:9000/oauth2/authorize")!,
    tokenEndpoint: URL(string: "http://localhost:9000/oauth2/token")!
)

let request = OIDAuthorizationRequest(
    configuration: config,
    clientId: "public-client",
    scopes: ["openid", "profile", "email", "read", "write"],
    redirectURL: URL(string: "myapp://callback")!,
    responseType: OIDResponseTypeCode,
    additionalParameters: nil
)

OIDAuthorizationService.present(request, presenting: self) { response, error in
    guard let response = response else {
        return
    }
    // Exchange authorization code for tokens
}
```

## Common OAuth Parameters

### Authorization Request Parameters

| Parameter | Required | Description |
|-----------|----------|-------------|
| response_type | Yes | Must be "code" |
| client_id | Yes | Client identifier |
| redirect_uri | Yes | Callback URL (must match registered) |
| scope | No | Space-separated list of scopes |
| state | Recommended | Random string to prevent CSRF |
| code_challenge | Yes (OAuth 2.1) | PKCE challenge |
| code_challenge_method | Yes | Must be "S256" |

### Token Request Parameters (Authorization Code)

| Parameter | Required | Description |
|-----------|----------|-------------|
| grant_type | Yes | Must be "authorization_code" |
| code | Yes | Authorization code from callback |
| redirect_uri | Yes | Same as authorization request |
| client_id | Yes | Client identifier |
| code_verifier | Yes (OAuth 2.1) | PKCE verifier |

### Token Request Parameters (Refresh Token)

| Parameter | Required | Description |
|-----------|----------|-------------|
| grant_type | Yes | Must be "refresh_token" |
| refresh_token | Yes | Current refresh token |
| client_id | Yes | Client identifier |
| scope | No | Requested scope (must be subset) |

### Token Request Parameters (Client Credentials)

| Parameter | Required | Description |
|-----------|----------|-------------|
| grant_type | Yes | Must be "client_credentials" |
| scope | No | Requested scopes |
| | | Requires Basic Auth header |

## Scopes Explained

| Scope | Description |
|-------|-------------|
| openid | Required for OpenID Connect |
| profile | Access to profile information |
| email | Access to email address |
| read | Read access to resources |
| write | Write access to resources |

## Token Response Structure

```json
{
  "access_token": "eyJraWQiOiI...",
  "refresh_token": "eyJhbGciOiJ...",
  "token_type": "Bearer",
  "expires_in": 900,
  "scope": "openid profile email read write",
  "id_token": "eyJhbGciOiJ..."
}
```

## JWT Access Token Claims

```json
{
  "sub": "user",
  "aud": "public-client",
  "nbf": 1701234567,
  "scope": ["openid", "profile", "email", "read", "write"],
  "iss": "http://localhost:9000",
  "exp": 1701235467,
  "iat": 1701234567,
  "jti": "550e8400-e29b-41d4-a716-446655440000"
}
```
