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
- Variables
- type DeviceCode
- type DeviceFlowError
- type Flow
- type Option
- type RedisStore
- func (s *RedisStore) CheckHealth(ctx context.Context) error
- func (s *RedisStore) DeleteDeviceCode(ctx context.Context, deviceCode string) error
- func (s *RedisStore) GetDeviceCode(ctx context.Context, deviceCode string) (*DeviceCode, error)
- func (s *RedisStore) GetDeviceCodeByUserCode(ctx context.Context, userCode string) (*DeviceCode, error)
- func (s *RedisStore) GetPollCount(ctx context.Context, deviceCode string, window time.Duration) (int, error)
- func (s *RedisStore) GetTokenResponse(ctx context.Context, deviceCode string) (*TokenResponse, error)
- func (s *RedisStore) IncrementPollCount(ctx context.Context, deviceCode string) error
- func (s *RedisStore) SaveDeviceCode(ctx context.Context, code *DeviceCode) error
- func (s *RedisStore) SaveTokenResponse(ctx context.Context, deviceCode string, token *TokenResponse) error
- func (s *RedisStore) UpdatePollTimestamp(ctx context.Context, deviceCode string) error
- type Store
- type TokenResponse
Constants ¶
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
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
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 ¶
var ( // Auth flow errors per RFC 8628 section 3.5 ErrInvalidDeviceCode = NewDeviceFlowError(ErrorCodeInvalidGrant, ErrorDescInvalidDeviceCode) ErrExpiredCode = NewDeviceFlowError(ErrorCodeExpiredToken, ErrorDescExpiredToken) ErrPendingAuthorization = NewDeviceFlowError(ErrorCodeAuthorizationPending, ErrorDescAuthorizationPending) ErrSlowDown = NewDeviceFlowError(ErrorCodeSlowDown, ErrorDescSlowDown) ErrAccessDenied = NewDeviceFlowError(ErrorCodeAccessDenied, ErrorDescAccessDenied) ErrServerError = NewDeviceFlowError(ErrorCodeServerError, ErrorDescServerError) // Request validation errors per RFC 8628 section 3.1 ErrMissingClientID = NewDeviceFlowError(ErrorCodeInvalidRequest, ErrorDescMissingClientID) ErrDuplicateParams = NewDeviceFlowError(ErrorCodeInvalidRequest, ErrorDescDuplicateParams) ErrInvalidRequest = NewDeviceFlowError(ErrorCodeInvalidRequest, ErrorDescInvalidRequestFormat) // Grant type errors per RFC 8628 section 3.4 ErrMissingGrantType = NewDeviceFlowError(ErrorCodeInvalidRequest, ErrorDescMissingGrantType) ErrMissingDeviceCode = NewDeviceFlowError(ErrorCodeInvalidRequest, ErrorDescMissingDeviceCode) ErrUnsupportedGrant = NewDeviceFlowError(ErrorCodeUnsupportedGrant, ErrorDescUnsupportedGrant) // Input validation errors ErrInvalidUserCode = NewDeviceFlowError(ErrorCodeInvalidRequest, ErrorDescInvalidUserCode) ErrRateLimitExceeded = NewDeviceFlowError(ErrorCodeSlowDown, ErrorDescRateLimitExceeded) )
Common errors that occur during the device authorization flow
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
type Option ¶
type Option func(*flowImpl)
Option configures the device flow implementation
func WithExpiryDuration ¶
WithExpiryDuration sets the code expiry duration per RFC 8628 section 3.2, expires_in must be greater than min duration
func WithPollInterval ¶
WithPollInterval sets the minimum polling interval per RFC 8628 section 3.5, clients must wait between polling attempts
func WithRateLimit ¶
WithRateLimit sets rate limiting parameters for token polling per RFC 8628 section 3.5, servers should enforce rate limits
func WithUserCodeLength ¶
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