> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth2

> OAuth 2.0 authentication middleware for third-party login integration.

## Overview

The `oauth2` middleware provides OAuth 2.0 authentication flows for integrating with providers like Google, GitHub, Facebook, and custom OAuth servers.

Use it when you need:

* Social login (Google, GitHub, etc.)
* Third-party authentication
* OAuth 2.0 authorization code flow

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/oauth2"
```

## Quick Start

```go theme={null}
app := mizu.New()

// Configure OAuth provider
config := oauth2.Config{
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret",
    RedirectURL:  "http://localhost:3000/callback",
    AuthURL:      "https://provider.com/oauth/authorize",
    TokenURL:     "https://provider.com/oauth/token",
    Scopes:       []string{"email", "profile"},
}

app.Get("/login", oauth2.Login(config))
app.Get("/callback", oauth2.Callback(config, handleUser))
```

## Configuration

### Config

| Field | Type | Description |
| - | - | - |
| `ClientID` | `string` | OAuth client ID |
| `ClientSecret` | `string` | OAuth client secret |
| `RedirectURL` | `string` | Callback URL |
| `AuthURL` | `string` | Provider's auth endpoint |
| `TokenURL` | `string` | Provider's token endpoint |
| `Scopes` | `[]string` | Requested scopes |

## Examples

### Google OAuth

```go theme={null}
config := oauth2.Google(oauth2.Config{
    ClientID:     os.Getenv("GOOGLE_CLIENT_ID"),
    ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
    RedirectURL:  "http://localhost:3000/auth/google/callback",
    Scopes:       []string{"email", "profile"},
})

app.Get("/auth/google", oauth2.Login(config))
app.Get("/auth/google/callback", oauth2.Callback(config, func(c *mizu.Ctx, token *oauth2.Token, user *oauth2.User) error {
    // User authenticated successfully
    session.Get(c).Set("user_id", user.ID)
    return c.Redirect(302, "/dashboard")
}))
```

### GitHub OAuth

```go theme={null}
config := oauth2.GitHub(oauth2.Config{
    ClientID:     os.Getenv("GITHUB_CLIENT_ID"),
    ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
    RedirectURL:  "http://localhost:3000/auth/github/callback",
    Scopes:       []string{"user:email"},
})

app.Get("/auth/github", oauth2.Login(config))
app.Get("/auth/github/callback", oauth2.Callback(config, handleGitHubUser))
```

### Custom Provider

```go theme={null}
config := oauth2.Config{
    ClientID:     "client-id",
    ClientSecret: "client-secret",
    RedirectURL:  "http://localhost:3000/callback",
    AuthURL:      "https://auth.example.com/authorize",
    TokenURL:     "https://auth.example.com/token",
    UserInfoURL:  "https://api.example.com/userinfo",
    Scopes:       []string{"openid", "profile"},
}
```

### State Parameter

```go theme={null}
app.Get("/login", oauth2.LoginWithState(config, func(c *mizu.Ctx) string {
    // Generate state with return URL
    return base64.URLEncoding.EncodeToString([]byte(c.Query("return_url")))
}))
```

## API Reference

### Functions

```go theme={null}
// Login starts OAuth flow
func Login(config Config) mizu.Handler

// LoginWithState starts flow with custom state
func LoginWithState(config Config, stateFn func(*mizu.Ctx) string) mizu.Handler

// Callback handles OAuth callback
func Callback(config Config, handler CallbackHandler) mizu.Handler

// Provider presets
func Google(config Config) Config
func GitHub(config Config) Config
func Facebook(config Config) Config
```

### Types

```go theme={null}
type Token struct {
    AccessToken  string
    RefreshToken string
    Expiry       time.Time
}

type User struct {
    ID       string
    Email    string
    Name     string
    Picture  string
    Provider string
}

type CallbackHandler func(*mizu.Ctx, *Token, *User) error
```

## Technical Details

### Architecture

The OAuth2 middleware is designed as a resource server implementation that validates OAuth 2.0 access tokens. It follows a flexible architecture that supports multiple validation strategies:

1. **Token Extraction**: Supports multiple token sources (header, query, form) via configurable `TokenLookup` parameter
2. **Token Validation**: Two validation strategies:
   * Custom validator function for flexibility
   * Token introspection endpoint (RFC 7662) for standard OAuth servers
3. **Scope Verification**: Automatic scope checking against required scopes
4. **Context Storage**: Validated token information is stored in request context for downstream handlers

### Token Validation Flow

1. Extract token from request based on `TokenLookup` configuration
2. Validate token using:
   * Custom `Validator` function if provided, or
   * OAuth 2.0 token introspection endpoint
3. Check token expiration if `ExpiresAt` is set
4. Verify required scopes match token scopes
5. Store validated token in context
6. Pass request to next handler

### Token Introspection

When using the introspection endpoint, the middleware:

* Sends POST request to `IntrospectionURL` with token
* Uses Basic authentication with `ClientID` and `ClientSecret` if provided
* Parses introspection response according to RFC 7662
* Validates the `active` field and extracts token metadata (subject, scopes, expiry)

### Error Handling

The middleware returns appropriate HTTP status codes:

* `401 Unauthorized`: Missing, invalid, or expired tokens
* `403 Forbidden`: Insufficient scopes
* Sets `WWW-Authenticate: Bearer` header on errors

Custom error handling can be implemented via the `ErrorHandler` option.

### Context Access

Helper functions provide convenient access to token information:

* `Get(c)`: Retrieves full token object
* `Subject(c)`: Gets token subject
* `Scopes(c)`: Returns token scopes
* `HasScope(c, scope)`: Checks for specific scope

### Scope Middleware

The `RequireScopes` middleware can be chained after the main OAuth2 middleware to enforce scope requirements at specific routes or route groups.

## Security Considerations

1. **Store secrets securely** - Use environment variables
2. **Validate state parameter** - Prevents CSRF attacks
3. **Use HTTPS** - Required for production OAuth
4. **Verify tokens** - Check expiration and validity
5. **Limit scopes** - Request only needed permissions

## Best Practices

* Store tokens securely (encrypted if stored)
* Implement token refresh for long sessions
* Handle callback errors gracefully
* Log OAuth events for security monitoring

## Testing

The OAuth2 middleware includes comprehensive test coverage for all functionality:

| Test Case | Description | Expected Behavior |
| - | - | - |
| `TestNew` - valid token | Request with valid Bearer token | Returns 200 OK, token validated |
| `TestNew` - invalid token | Request with invalid Bearer token | Returns 401 Unauthorized |
| `TestNew` - missing token | Request without Authorization header | Returns 401 Unauthorized |
| `TestWithOptions_RequiredScopes` | Token with insufficient scopes | Returns 403 Forbidden |
| `TestWithOptions_ExpiredToken` | Token with past expiration time | Returns 401 Unauthorized |
| `TestGet` | Retrieve token from context | Token object accessible via Get() |
| `TestSubject` | Extract subject from token | Subject field returned correctly |
| `TestHasScope` | Check for specific scope | Returns true/false based on presence |
| `TestRequireScopes` | Scope enforcement middleware | Blocks request if scopes missing |
| `TestWWWAuthenticateHeader` | Invalid token response | WWW-Authenticate header present |
| `TestExtractToken_Query` | Token in query parameter | Token extracted from URL query |
| `TestExtractToken_Form` | Token in form body | Token extracted from form data |
| `TestExtractToken_InvalidLookup` | Malformed TokenLookup config | Returns 401, no token found |
| `TestExtractToken_UnknownSource` | Unknown token source type | Returns 401, no token found |
| `TestExtractToken_HeaderWithoutBearer` | Plain token without Bearer prefix | Token extracted and validated |
| `TestWithOptions_NoValidator` | No validator configured | Returns 401 with ErrNoValidator |
| `TestWithOptions_CustomErrorHandler` | Custom error handler set | Custom handler invoked on error |
| `TestIntrospectToken` - active | Introspection returns active token | Returns 200 OK |
| `TestIntrospectToken` - inactive | Introspection returns inactive token | Returns 401 Unauthorized |
| `TestIntrospectToken_ServerError` | Introspection endpoint error | Returns 401 Unauthorized |
| `TestIntrospectToken_InvalidJSON` | Malformed introspection response | Returns 401 Unauthorized |
| `TestIntrospectToken_ConnectionError` | Cannot connect to endpoint | Returns 401 Unauthorized |
| `TestGet_NoToken` | Get() without middleware | Returns nil |
| `TestSubject_NoToken` | Subject() without token | Returns empty string |
| `TestScopes` | Retrieve scopes list | Returns all token scopes |
| `TestScopes_NoToken` | Scopes() without token | Returns nil |
| `TestRequireScopes_NoToken` | RequireScopes without auth | Returns 401 Unauthorized |
| `TestRequireScopes_Sufficient` | Token has required scopes | Returns 200 OK, access granted |
| `TestHasScope_NoToken` | HasScope() without token | Returns false |
| `TestErrorTypes` | Error message strings | All error types return correct messages |
| `TestWithOptions_IntrospectionWithoutClientCreds` | Introspection without client auth | No Basic auth sent, request succeeds |

## Related Middlewares

* [oidc](/middlewares/oidc) - OpenID Connect
* [jwt](/middlewares/jwt) - JWT authentication
* [session](/middlewares/session) - Session management


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.