devicelogin

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package devicelogin pairs an unauthenticated browser with an explicitly approving signed-in user. Pending requests are memory-only: restart cancels them. Hosts must mount all handlers behind their existing network/origin protections, provide trusted client IPs, and issue their normal session.

Browser pairing storage, approval proofs, and bounded abuse budgets.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func UserAgent

func UserAgent(agent string) string

UserAgent bounds browser metadata to 256 bytes while preserving valid UTF-8. Invalid bytes and a partial trailing character are removed. Hosts can use the same representation in their normal session metadata and device approval UI.

Types

type AuditEvent

type AuditEvent struct {
	RequestID string
	SessionID string
	Kind      AuditKind
	Subject   string
	Approved  bool
	IP        string
	UserAgent string
	CreatedAt time.Time
}

AuditEvent correlates decisions and session-completion outcomes without credentials or user codes.

type AuditKind

type AuditKind string

AuditKind identifies a pairing or session-completion outcome. ResponseWritten records only a successful local write; client receipt is always unknown.

const (
	AuditDecision                 AuditKind = "decision"
	AuditIssuanceStarted          AuditKind = "issuance_started"
	AuditResponseFailed           AuditKind = "response_failed"
	AuditResponseWritten          AuditKind = "response_written"
	AuditRevocationFailed         AuditKind = "revocation_failed"
	AuditSessionCreated           AuditKind = "session_created"
	AuditSessionCreationUncertain AuditKind = "session_creation_uncertain"
	AuditSessionFailed            AuditKind = "session_failed"
	AuditSessionRevoked           AuditKind = "session_revoked"
)

Audit kinds distinguish durable decisions, creation, local writes, and cleanup.

type Host

type Host interface {
	Enabled() bool
	ClientIP(*http.Request) netip.Addr
	VerificationURL(*http.Request) string
	Identify(*http.Request) (string, error)
	Eligible(context.Context, string) error
	CreateSession(*http.Request, string) (Session, error)
	Audit(context.Context, *AuditEvent) error
}

Host supplies host policy without sharing account or session types. Identity must be stable and sufficient to recheck current login policy. CreateSession must return a nonnil Session whenever it created one, including on error, so failure can revoke it. Use the host's normal issuer with its ordinary permissions, lifetime, and capabilities. Audit must persist the event before returning nil and must not mutate or retain it. Methods must support concurrent calls.

type LookupResponse

type LookupResponse struct {
	UserCode  string    `json:"user_code"`
	IP        string    `json:"ip"`
	UserAgent string    `json:"user_agent"`
	CreatedAt time.Time `json:"created_at"`
	ExpiresAt time.Time `json:"expires_at"`
	CSRFToken string    `json:"csrf_token"`
}

LookupResponse describes the requesting browser and a short-lived subject-bound CSRF token.

type Server

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

Server owns a bounded in-memory device login store. Use one Server per host process. Multi-instance hosts need sticky routing for these endpoints. Codes expire in ten minutes.

func New

func New(host Host) *Server

New creates a pairing server. The host must be initialized and nonnil.

func (*Server) Approve

func (s *Server) Approve(w http.ResponseWriter, r *http.Request)

Approve records an explicit approval or denial. X-Device-Login-CSRF must contain the token from Lookup for this subject and code; JSON and a custom header prevent cookie CSRF.

func (*Server) Lookup

func (s *Server) Lookup(w http.ResponseWriter, r *http.Request)

Lookup requires an eligible signed-in approver, rate limits all guesses, and reveals no device secret.

func (*Server) Poll

func (s *Server) Poll(w http.ResponseWriter, r *http.Request)

Poll consumes an approval before attempting session creation. Every completion failure (including cancellation or lost delivery) requires a new code; replay cannot create a second session. Failed writes and audit failures trigger revocation; cleanup failures are audited and logged. A successful write does not prove receipt.

func (*Server) Start

func (s *Server) Start(w http.ResponseWriter, r *http.Request)

Start creates a code. Per-IP and global creation budgets also bound memory and abuse.

type Session

type Session interface {
	SessionID() string
	WriteResponse(http.ResponseWriter) error
	Revoke(context.Context) error
}

Session is a newly persisted host session. The host retains its credential and response/account types. WriteResponse must report serialization or write failures; Revoke must durably invalidate the session even when the original request was cancelled.

type StartResponse

type StartResponse struct {
	RequestID       string `json:"request_id"`
	DeviceCode      string `json:"device_code"`
	UserCode        string `json:"user_code"`
	VerificationURI string `json:"verification_uri"`
	ExpiresIn       int    `json:"expires_in"`
	Interval        int    `json:"interval"`
}

StartResponse is the display's private authorization request. Never send DeviceCode to the approver.

Jump to

Keyboard shortcuts

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