devicegrant

package
v0.42.2 Latest Latest
Warning

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

Go to latest
Published: Nov 10, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package devicegrant holds the pending sign-ins of the OAuth 2.0 device authorization grant (RFC 8628), which `knot connect` uses: the client gets a device code it keeps and a short user code it shows, the user approves the user code in the web interface, and the client polls the token endpoint with the device code until it gets its API token.

State is in-memory per server; Grant/Apply exist so servers gossip every change over the cluster, so the approval and the polls may land on different servers behind a load balancer.

Index

Constants

View Source
const (
	// TTL is how long a device sign-in waits for its user.
	TTL = 10 * time.Minute
	// Interval is the minimum number of seconds between polls.
	Interval = 5
)

Variables

View Source
var (

	// ErrTooMany is returned by New when too many sign-ins are waiting.
	ErrTooMany = errors.New("too many device sign-ins waiting")
)

Functions

func Apply

func Apply(g *Grant)

Apply records a grant change from this or another server. A change is ignored unless it moves the grant's status forward.

func FormatUserCode

func FormatUserCode(c string) string

FormatUserCode shows a normalised code as two groups: WDJB-MJHT.

func NormUserCode

func NormUserCode(typed string) string

NormUserCode turns what someone typed into a normalised code: case, spaces and dashes do not matter. It returns "" for anything that cannot be a code.

Types

type Grant

type Grant struct {
	DeviceCode string    `msgpack:"device_code"`
	UserCode   string    `msgpack:"user_code"` // normalised, no separator
	TokenName  string    `msgpack:"token_name"`
	ExpiresAt  time.Time `msgpack:"expires_at"`
	Status     Status    `msgpack:"status"`
	UserId     string    `msgpack:"user_id,omitempty"`
	TokenId    string    `msgpack:"token_id,omitempty"` // set on approval
}

Grant is a device sign-in, gossiped between servers on every change.

func ByDeviceCode

func ByDeviceCode(deviceCode string) (g *Grant, slowDown bool)

ByDeviceCode returns the sign-in of a device code, for a poll of the token endpoint. slowDown is true when the poll came sooner than the device's interval, which then grows by 5 seconds (RFC 8628 section 3.5).

func ByUserCode

func ByUserCode(userId, typed string) (g *Grant, limited bool)

ByUserCode finds the pending, unexpired sign-in a user typed the code of. Wrong codes count against userId; once it has made too many in the last 15 minutes, every code is refused and limited is true.

func New

func New(tokenName string) (*Grant, error)

New starts a device sign-in for a token with the given name.

func (*Grant) Expired

func (g *Grant) Expired() bool

type Status

type Status int
const (
	StatusPending Status = iota
	StatusApproved
	StatusDenied
	StatusUsed
)

The statuses only move forward, so gossip applied in any order converges.

Jump to

Keyboard shortcuts

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