oauth2x

package
v1.1.19 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2025 License: MIT Imports: 7 Imported by: 0

README

OAuth2X

OAuth2X provides an enhanced OAuth2 client that improves upon the standard oauth2.Transport. It offers better control over token refresh and authentication failures.

Key Features

  • Client-Level Token Refresh: Token refresh is handled at the client level instead of transport level
  • Token Change Hooks: Callbacks for token refresh events, making it easy to persist new tokens
  • Error Handling: Customizable error handling for authentication failures
  • Flexible Configuration: Multiple hooks for different authentication scenarios
  • Compatible API: Fully compatible with the standard oauth2.Transport

Basic Usage

// Create a client with OAuth2 support
client := httpx.NewXClient(
    WithOAuth2Http(ctx, currentToken, tokenSource,
        WithOnRefreshTokenChange(func(ctx context.Context, newToken *oauth2.Token) error {
            // Save the new token when it changes
            return db.SaveToken(newToken)
        }),
        WithAuthError(ErrCustomAuth),
    ),
)

// Make requests as usual - token handling is automatic
var response struct {
    Data string `json:"data"`
}
err := client.GetJSON(ctx, "https://api.example.com/protected", &response)

Architecture

OAuth2X is built on top of the httpx.Client interface and integrates seamlessly with the HTTPX package. It handles:

  1. Automatic token refresh when needed
  2. Token persistence through callbacks
  3. Custom error handling for authentication failures
  4. Proper cleanup of resources

Options

OAuth2 Options
  • WithOnRefreshTokenChange(func): Callback when refresh token changes
  • WithOnAuthError(func): Callback for authentication failures
  • WithAuthError(error): Custom error for auth failures
  • WithRecordError(func): Callback for internal errors

Error Handling

Authentication failures can occur in several scenarios:

  • Token refresh fails
  • Token persistence fails
  • Server returns 401/403 response

You can handle these cases by:

  1. Setting a custom error with WithAuthError
  2. Registering callbacks with WithOnAuthError
  3. Logging internal errors with WithRecordError
client := httpx.NewXClient(
    WithOAuth2Http(ctx, token, source,
        WithAuthError(ErrAuthExpired),
        WithOnAuthError(func(ctx context.Context, token *oauth2.Token, err error) {
            log.Printf("Auth failed: %v", err)
        }),
    ),
)

Migration from oauth2.Transport

OAuth2X is designed to be a drop-in replacement for oauth2.Transport. The main differences are:

  1. Token refresh happens at the client level
  2. You can hook into token refresh events
  3. You have more control over error handling
  4. Response bodies are automatically closed on errors

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func WithOAuth2Http

func WithOAuth2Http(
	ctx context.Context,
	currentToken *oauth2.Token,
	tokenSource oauth2.TokenSource,
	opts ...OAuth2HttpOption,
) httpx.ClientDecorator

WithOAuth2Http creates a ClientDecorator that adds OAuth2 authentication to an HTTP client. It will use the provided token source for authentication and handle token refresh automatically.

Example:

client := httpx.NewXClient(
    WithOAuth2Http(ctx, currentToken, tokenSource,
        WithOnRefreshTokenChange(func(ctx context.Context, newToken *oauth2.Token) error {
            return saveNewToken(newToken)
        }),
        WithAuthError(ErrCustomAuth),
    ),
)

Types

type OAuth2Core

type OAuth2Core struct {
	// Source supplies the token to add to outgoing requests'
	// Authorization headers.
	Source oauth2.TokenSource

	// Inner is the wrapped httpx.Client used to make HTTP requests.
	// If nil, http.DefaultClient is used.
	Inner httpx.Client

	Ctx                      context.Context
	ErrAuthenticationInvalid error  // error to return when RefreshTokenFailed / AuthorizationFailed
	CurrentRefreshToken      string // used to compare with the new token
	OnRefreshTokenChange     func(ctx context.Context, newToken *oauth2.Token) error
	OnAuthError              func(ctx context.Context, oldToken *oauth2.Token, refreshErr error)
	OnRecordError            func(ctx context.Context, err error)
}

OAuth2Core is an httpx.Client that handles OAuth2 authentication automatically. It is based on oauth2.Transport but with the following improvements: 1. Token refresh is handled at the client level instead of transport level 2. Provides hooks for token refresh events 3. Returns specific errors for authentication failures

Example usage:

core := &OAuth2Core{
    Source: oauth2.StaticTokenSource(initialToken),
    OnRefreshTokenChange: func(ctx context.Context, newToken *oauth2.Token) error {
        // Save the new token
        return saveToken(newToken)
    },
}

func (*OAuth2Core) Do

func (t *OAuth2Core) Do(req *http.Request) (*http.Response, error)

Do authorizes and authenticates the request with an access token. It will: 1. Get a valid token from the TokenSource 2. Trigger OnRefreshTokenChange if the refresh token has changed 3. Add the token to the request's Authorization header 4. Execute the request 5. Handle authentication errors (401/403) by returning ErrAuthenticationInvalid

Note: When returning an error, the response body will be closed automatically.

type OAuth2HttpOption

type OAuth2HttpOption func(t *OAuth2Core)

func WithAuthError

func WithAuthError(err error) OAuth2HttpOption

WithAuthError configures the error that will be returned for all authentication failures. When set, this error will be returned instead of the original error for: - Token refresh failures - OnRefreshTokenChange callback errors - 401/403 responses from the server

If not set, the original error will be returned.

Example:

var ErrAuthExpired = errors.New("authentication expired")
client := NewXClient(WithOAuth2Http(ctx, token, source,
    WithAuthError(ErrAuthExpired),
))

func WithOnAuthError

func WithOnAuthError(onRefreshTokenFailed func(ctx context.Context, oldToken *oauth2.Token, refreshErr error)) OAuth2HttpOption

WithOnAuthError sets a callback that is triggered when any authentication error occurs. This includes token refresh failures, OnRefreshTokenChange errors, and 401/403 responses. The callback receives the token that was used in the failed request and the error that occurred.

This is useful for logging authentication failures or updating metrics. The callback is called before returning ErrAuthenticationInvalid (if configured).

Example:

WithOnAuthError(func(ctx context.Context, oldToken *oauth2.Token, err error) {
    log.Printf("Auth failed for user %v: %v", oldToken.AccessToken, err)
    metrics.AuthFailures.Inc()
})

func WithOnRefreshTokenChange

func WithOnRefreshTokenChange(onRefreshTokenChange func(ctx context.Context, newToken *oauth2.Token) error) OAuth2HttpOption

WithOnRefreshTokenChange sets a callback that is triggered when the refresh token changes. This is useful for persisting the new token for future use. If the callback returns an error, the request will fail with ErrAuthenticationInvalid (if configured) or the original error.

Example:

WithOnRefreshTokenChange(func(ctx context.Context, newToken *oauth2.Token) error {
    return db.SaveToken(newToken)
})

func WithRecordError

func WithRecordError(onRecordError func(ctx context.Context, err error)) OAuth2HttpOption

WithRecordError sets a callback for recording internal errors that occur during authentication but don't affect the request outcome. Currently this is only used for errors that occur while reading the response body of a failed authentication attempt.

Example:

WithRecordError(func(ctx context.Context, err error) {
    log.Printf("Internal oauth error: %v", err)
})

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL