deviceflow

package
v0.0.0-...-18d7262 Latest Latest
Warning

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

Go to latest
Published: Dec 17, 2024 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package deviceflow implements OAuth2 device flow code generation per RFC 8628

Package deviceflow implements OAuth 2.0 Device Authorization Grant per RFC 8628 RFC 8628" aria-label="Go to Package deviceflow implements OAuth 2.0 Device Authorization Grant per RFC 8628">¶

Package deviceflow implements OAuth 2.0 Device Authorization Grant per RFC 8628 RFC 8628" aria-label="Go to Package deviceflow implements OAuth 2.0 Device Authorization Grant per RFC 8628">¶

Package deviceflow implements OAuth 2.0 Device Authorization Grant (RFC 8628)

Package deviceflow implements device authorization storage with Redis

Package deviceflow implements OAuth 2.0 Device Authorization Grant (RFC 8628)

Package deviceflow implements test helpers for device flow tests

Package deviceflow implements URI handling for OAuth 2.0 Device Flow

Package deviceflow implements verification for OAuth 2.0 Device Flow

Index

Constants

View Source
const (
	ErrorCodeAuthorizationPending = "authorization_pending"
	ErrorCodeSlowDown             = "slow_down"
	ErrorCodeAccessDenied         = "access_denied"
	ErrorCodeExpiredToken         = "expired_token"
	ErrorCodeInvalidGrant         = "invalid_grant"
	ErrorCodeInvalidRequest       = "invalid_request"
	ErrorCodeUnsupportedGrant     = "unsupported_grant_type"
	ErrorCodeServerError          = "server_error" // For internal server errors
)

Error codes defined by RFC 8628 section 3.5

View Source
const (
	// Section 3.1 error descriptions
	ErrorDescMissingClientID      = "The client_id parameter is REQUIRED"
	ErrorDescDuplicateParams      = "Parameters MUST NOT be included more than once"
	ErrorDescInvalidRequestFormat = "Invalid request format"

	// Section 3.4 error descriptions
	ErrorDescMissingGrantType  = "The grant_type parameter is REQUIRED"
	ErrorDescMissingDeviceCode = "The device_code parameter is REQUIRED"
	ErrorDescUnsupportedGrant  = "Only urn:ietf:params:oauth:grant-type:device_code is supported"

	// Section 3.5 error descriptions
	ErrorDescAuthorizationPending = "The authorization request is still pending"
	ErrorDescSlowDown             = "Polling interval must be increased by 5 seconds"
	ErrorDescAccessDenied         = "The user denied the authorization request"
	ErrorDescExpiredToken         = "The device_code has expired"
	ErrorDescInvalidDeviceCode    = "The device_code is invalid or malformed"
	ErrorDescServerError          = "An unexpected error occurred"

	// Section 6.1 error descriptions
	ErrorDescInvalidUserCode   = "Invalid user code format"
	ErrorDescRateLimitExceeded = "Too many verification attempts"
)

Error descriptions defined by RFC 8628

View Source
const (
	// MinExpiryDuration defines the minimum expiry duration per RFC 8628
	MinExpiryDuration = 10 * time.Minute

	// MinPollInterval is the minimum interval between polling requests
	MinPollInterval = 5 * time.Second

	// DeviceCodeLength is the required length of the device code in hex characters
	DeviceCodeLength = 64 // 32 bytes hex encoded per tests
)

Variables

Common errors that occur during the device authorization flow

View Source
var ErrStoreUnhealthy = errors.New("store unhealthy")

ErrStoreUnhealthy indicates the store is not available

Functions

This section is empty.

Types

type DeviceCode

type DeviceCode struct {
	// Required fields per RFC 8628 section 3.2
	DeviceCode      string `json:"device_code"`
	UserCode        string `json:"user_code"`
	VerificationURI string `json:"verification_uri"`
	// ExpiresIn is required and must be calculated based on remaining time
	ExpiresIn int `json:"expires_in"` // Remaining time in seconds
	// Interval sets minimum polling wait time
	Interval int `json:"interval"` // Poll interval in seconds

	// Optional verification_uri_complete field per RFC 8628 section 3.3.1
	// Enables non-textual transmission of the verification URI (e.g., QR codes)
	// The URI includes the user code to minimize user input required
	VerificationURIComplete string `json:"verification_uri_complete,omitempty"`

	// Required response fields per RFC 8628 section 3.2
	ExpiresAt time.Time `json:"expires_at"` // Absolute expiry time
	ClientID  string    `json:"client_id"`  // OAuth2 client identifier
	Scope     string    `json:"scope"`      // OAuth2 scope
	LastPoll  time.Time `json:"last_poll"`  // Last poll timestamp
}

DeviceCode represents the device authorization details per RFC 8628 section 3.2

type DeviceFlowError

type DeviceFlowError struct {
	Code        string `json:"error"`
	Description string `json:"error_description,omitempty"`
}

DeviceFlowError represents a structured error response per RFC 8628

func AsDeviceFlowError

func AsDeviceFlowError(err error) (*DeviceFlowError, bool)

AsDeviceFlowError attempts to convert an error to a DeviceFlowError

func NewDeviceFlowError

func NewDeviceFlowError(code string, description string) *DeviceFlowError

NewDeviceFlowError creates a new device flow error with description

func (*DeviceFlowError) Error

func (e *DeviceFlowError) Error() string

Error implements the error interface

type Flow

type Flow interface {
	// RequestDeviceCode initiates a new device authorization request
	RequestDeviceCode(ctx context.Context, clientID string, scope string) (*DeviceCode, error)

	// GetDeviceCode retrieves and validates a device code
	GetDeviceCode(ctx context.Context, deviceCode string) (*DeviceCode, error)

	// CheckDeviceCode validates device code and returns token if authorized
	CheckDeviceCode(ctx context.Context, deviceCode string) (*TokenResponse, error)

	// VerifyUserCode validates user code and returns associated device code
	VerifyUserCode(ctx context.Context, userCode string) (*DeviceCode, error)

	// CompleteAuthorization completes the authorization flow for a device code
	CompleteAuthorization(ctx context.Context, deviceCode string, token *TokenResponse) error

	// CheckHealth verifies the flow manager's storage backend is healthy
	CheckHealth(ctx context.Context) error
}

Flow defines the interface for device authorization grant flow per RFC 8628

func NewFlow

func NewFlow(store Store, baseURL string, opts ...Option) Flow

NewFlow creates a new device flow manager with provided options

type Option

type Option func(*flowImpl)

Option configures the device flow implementation

func WithExpiryDuration

func WithExpiryDuration(d time.Duration) Option

WithExpiryDuration sets the code expiry duration per RFC 8628 section 3.2, expires_in must be greater than min duration

func WithPollInterval

func WithPollInterval(d time.Duration) Option

WithPollInterval sets the minimum polling interval per RFC 8628 section 3.5, clients must wait between polling attempts

func WithRateLimit

func WithRateLimit(window time.Duration, maxPolls int) Option

WithRateLimit sets rate limiting parameters for token polling per RFC 8628 section 3.5, servers should enforce rate limits

func WithUserCodeLength

func WithUserCodeLength(length int) Option

WithUserCodeLength sets the user code length length must be compatible with RFC 8628 section 6.1 requirements

type RedisStore

type RedisStore struct {
	// contains filtered or unexported fields
}

RedisStore implements the Store interface using Redis

func (*RedisStore) CheckHealth

func (s *RedisStore) CheckHealth(ctx context.Context) error

CheckHealth verifies Redis connectivity

func (*RedisStore) DeleteDeviceCode

func (s *RedisStore) DeleteDeviceCode(ctx context.Context, deviceCode string) error

DeleteDeviceCode removes a device code and associated data

func (*RedisStore) GetDeviceCode

func (s *RedisStore) GetDeviceCode(ctx context.Context, deviceCode string) (*DeviceCode, error)

GetDeviceCode retrieves a device code

func (*RedisStore) GetDeviceCodeByUserCode

func (s *RedisStore) GetDeviceCodeByUserCode(ctx context.Context, userCode string) (*DeviceCode, error)

GetDeviceCodeByUserCode retrieves a device code using the user code

func (*RedisStore) GetPollCount

func (s *RedisStore) GetPollCount(ctx context.Context, deviceCode string, window time.Duration) (int, error)

GetPollCount gets the number of polls in the given window

func (*RedisStore) GetTokenResponse

func (s *RedisStore) GetTokenResponse(ctx context.Context, deviceCode string) (*TokenResponse, error)

GetTokenResponse retrieves a stored token response for a device code

func (*RedisStore) IncrementPollCount

func (s *RedisStore) IncrementPollCount(ctx context.Context, deviceCode string) error

IncrementPollCount increments the poll counter with timestamp

func (*RedisStore) SaveDeviceCode

func (s *RedisStore) SaveDeviceCode(ctx context.Context, code *DeviceCode) error

SaveDeviceCode stores a device code with expiration

func (*RedisStore) SaveTokenResponse

func (s *RedisStore) SaveTokenResponse(ctx context.Context, deviceCode string, token *TokenResponse) error

SaveTokenResponse stores a token response for a device code per RFC 8628

func (*RedisStore) UpdatePollTimestamp

func (s *RedisStore) UpdatePollTimestamp(ctx context.Context, deviceCode string) error

UpdatePollTimestamp updates the last poll timestamp

type Store

type Store interface {
	// SaveDeviceCode stores a device code with its associated data
	SaveDeviceCode(ctx context.Context, code *DeviceCode) error

	// GetDeviceCode retrieves a device code by its device code string
	GetDeviceCode(ctx context.Context, deviceCode string) (*DeviceCode, error)

	// GetDeviceCodeByUserCode retrieves a device code by its user code
	GetDeviceCodeByUserCode(ctx context.Context, userCode string) (*DeviceCode, error)

	// GetTokenResponse retrieves token response for a device code
	GetTokenResponse(ctx context.Context, deviceCode string) (*TokenResponse, error)

	// SaveTokenResponse stores token response for a device code
	SaveTokenResponse(ctx context.Context, deviceCode string, token *TokenResponse) error

	// DeleteDeviceCode removes a device code and its associated data
	DeleteDeviceCode(ctx context.Context, deviceCode string) error

	// GetPollCount gets the number of polls in the given window
	GetPollCount(ctx context.Context, deviceCode string, window time.Duration) (int, error)

	// UpdatePollTimestamp updates the last poll timestamp for rate limiting
	UpdatePollTimestamp(ctx context.Context, deviceCode string) error

	// IncrementPollCount increments the poll counter for rate limiting
	IncrementPollCount(ctx context.Context, deviceCode string) error

	// CheckHealth verifies the storage backend is healthy
	CheckHealth(ctx context.Context) error
}

Store defines the interface for device flow storage

func NewRedisStore

func NewRedisStore(client *redis.Client) Store

NewRedisStore creates a new Redis-backed store

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`            // The OAuth2 access token
	TokenType    string `json:"token_type"`              // Token type (usually "Bearer")
	ExpiresIn    int    `json:"expires_in"`              // Token validity in seconds
	RefreshToken string `json:"refresh_token,omitempty"` // Optional refresh token
	Scope        string `json:"scope,omitempty"`         // OAuth2 scope granted
}

TokenResponse represents the OAuth2 token response per RFC 8628 section 3.5

Jump to

Keyboard shortcuts

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