Help us shape the future of Go! Take the 2026 Go Developer Survey

authorization

package
v0.0.0-...-e29b97a Latest Latest
Warning

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

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

Documentation

Overview

Package authorization は認可エンドポイント(/authorize)の処理を担う。

認可要求の解析・検証、Authorization Transaction の状態機械、Interaction App との 契約(Begin / Complete / Reject / Resume)、PKCE の検証、Authorization Code の発行を 1 つの文脈として扱う(docs/adr/0003-interaction-contract.md、docs/adr/0007-package-layout.md)。

対応する仕様:

  • RFC 6749 §3.1 Authorization Endpoint、§4.1.1 Authorization Request、 §4.1.2 Authorization Response、§4.1.2.1 Error Response
  • RFC 7636 §4.3 code_challenge の送信、§4.4 サーバー側の保持
  • RFC 8707 §2.1 認可要求の resource パラメータ(設定と Client の許可範囲で検証し、 範囲外は invalid_target。Code に引き継ぐ)
  • RFC 9207 認可レスポンスの iss パラメータ
  • RFC 9700 §4.1 redirect_uri、§4.7 CSRF 対策(PKCE / state)
  • OIDC Core §3.1.2.1 Authentication Request(nonce, prompt, max_age, login_hint, ...)、 §3.1.2.6 Authentication Error Response

永続化の規約: Transaction と AuthorizationCode は公開フィールドの構造体だが、 構築はこのパッケージの Service が行い、状態遷移は Store.TransitionTransaction の CAS で原子的に行う。Status フィールドへの直接代入は Adapter の復元に限る。

Index

Examples

Constants

View Source
const (
	CodeInvalidRequest          = "invalid_request"
	CodeUnauthorizedClient      = "unauthorized_client"
	CodeAccessDenied            = "access_denied"
	CodeUnsupportedResponseType = "unsupported_response_type"
	CodeInvalidScope            = "invalid_scope"
	CodeServerError             = "server_error"
	CodeTemporarilyUnavailable  = "temporarily_unavailable"

	// CodeInvalidTarget は resource パラメータが不正、または設定・Client の許可範囲にない
	// Resource Server を指している(RFC 8707 §2)。
	CodeInvalidTarget = "invalid_target"

	CodeInteractionRequired    = "interaction_required"
	CodeLoginRequired          = "login_required"
	CodeConsentRequired        = "consent_required"
	CodeRequestNotSupported    = "request_not_supported"
	CodeRequestURINotSupported = "request_uri_not_supported"
)

RFC 6749 §4.1.2.1 と OIDC Core §3.1.2.6 のエラーコード。

View Source
const (
	DefaultTransactionTTL = 10 * time.Minute
	MaxTransactionTTL     = time.Hour
	DefaultCodeTTL        = time.Minute
	MaxCodeTTL            = 10 * time.Minute // RFC 6749 §4.1.2
)

期限の既定値と上限(ADR-0003 §5)。

View Source
const CodeChallengeMethodS256 = "S256"

CodeChallengeMethodS256 は唯一サポートする code_challenge_method(RFC 7636 §4.2、RFC 9700 §2.1.1)。 "plain" は受け付けない。

View Source
const ResumeTokenPrefix = "rs_"

ResumeTokenPrefix は Resume Token の接頭辞。

Variables

View Source
var (
	// ErrTransactionNotFound は Txn が存在しない(404)。
	ErrTransactionNotFound = errors.New("authorization: transaction not found")
	// ErrTransactionExpired は Txn が期限切れ(410)。
	ErrTransactionExpired = errors.New("authorization: transaction expired")
	// ErrTransactionNotPending は既に Complete / Reject 済み(409)。
	ErrTransactionNotPending = errors.New("authorization: transaction is not pending")
	// ErrInvalidOutcome は Outcome / Rejection の内容が契約に反する(400)。詳細は fmt で付加される。
	ErrInvalidOutcome = errors.New("authorization: invalid outcome")
	// ErrResumeDenied は Resume を拒否した(ResumeToken・ブラウザ結合の不一致、未完了、再利用)。
	// 攻撃者に区別を与えないため、理由は分けない。エラーページを描き、Client へはリダイレクトしない。
	ErrResumeDenied = errors.New("authorization: resume denied")
)

Interaction API(Complete / Reject / Resume)向けのエラー。HTTP 層はこれらをステータスに写す。

Functions

func ValidCodeChallenge

func ValidCodeChallenge(s string) bool

ValidCodeChallenge は code_challenge が RFC 7636 §4.2 の構文に従うかを返す。 S256 の値は base64url(パディングなし)の 43 文字で、unreserved 文字の部分集合である。

func ValidCodeVerifier

func ValidCodeVerifier(s string) bool

ValidCodeVerifier は code_verifier が RFC 7636 §4.1 の構文 (43〜128 文字の unreserved 文字 [A-Za-z0-9-._~])に従うかを返す。

func VerifyS256

func VerifyS256(challenge, verifier string) bool

VerifyS256 は BASE64URL(SHA256(code_verifier)) == code_challenge を定数時間で検証する (RFC 7636 §4.6)。

Example

ExampleVerifyS256 は PKCE の S256 検証(RFC 7636 §4.6)を、RFC 7636 Appendix B の値で確かめる。 エンジンは plain を受け付けないので、Client は常に BASE64URL(SHA256(code_verifier)) を送る。

package main

import (
	"fmt"

	"github.com/u-masato/auth-engine/authorization"
)

func main() {
	const (
		verifier  = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
		challenge = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
	)
	fmt.Println(authorization.VerifyS256(challenge, verifier))
	fmt.Println(authorization.VerifyS256(challenge, "wrong-verifier-wrong-verifier-wrong-verifier"))

}
Output:
true
false

Types

type AuthorizationCode

type AuthorizationCode struct {
	Hash string

	TxnID    string
	ClientID string
	GrantID  string
	// FamilyID は、この Code の交換で作られる Token Family の ID をあらかじめ確定したもの。
	// Code の再利用を検知したとき、この Family を失効させる(RFC 6749 §4.1.2)。
	FamilyID string

	Subject             string
	RedirectURI         string
	RedirectURIExplicit bool
	Scopes              []string
	CodeChallenge       string
	CodeChallengeMethod string
	Nonce               string
	// Resource は認可要求の resource をそのまま引き継いだもの(ADR-0008 §3)。
	// Code 交換で発行する Access Token の Audience はこの部分集合になる(RFC 8707 §2.2)。
	Resource []string

	AuthenticatedAt time.Time
	AMR             []string
	ACR             string
	Claims          map[string]any

	CreatedAt  time.Time
	ExpiresAt  time.Time
	ConsumedAt time.Time // ゼロ値なら未消費
}

AuthorizationCode は Resume 時に発行する単回使用の Code(RFC 6749 §4.1.2)。 Code の平文は保存せず、SHA-256 の Hash をキーにする。

func (*AuthorizationCode) Consumed

func (c *AuthorizationCode) Consumed() bool

Consumed は消費済みかを返す。

func (*AuthorizationCode) Expired

func (c *AuthorizationCode) Expired(now time.Time) bool

Expired は now 時点で期限切れかを返す。

type Error

type Error struct {
	Code        string
	Description string
	RedirectURI string
	State       string
	// Cause はログ用の内部原因。Client には返さない。
	Cause error
}

Error は認可エンドポイントのプロトコルエラー。

RedirectURI が空のときは client_id 不明または redirect_uri 不一致であり、 RFC 6749 §4.1.2.1 により Client へリダイレクトしてはならない。呼び出し側はエラーページを描く。 RedirectURI が非空なら RedirectURL で Client 向けのエラー応答 URL を組み立てる。

func (*Error) Error

func (e *Error) Error() string

func (*Error) RedirectURL

func (e *Error) RedirectURL(issuer string) string

RedirectURL は Client へのエラー応答 URL を返す(RFC 6749 §4.1.2.1、RFC 9207 の iss 付き)。 Redirectable でなければ空文字を返す。

func (*Error) Redirectable

func (e *Error) Redirectable() bool

Redirectable は Client へリダイレクトして返してよいエラーかを返す。

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap は Cause を返す。

type Outcome

type Outcome struct {
	// Subject はエンジンにとって不透明なユーザー識別子。
	Subject string
	// AuthenticatedAt は認証時刻。max_age の検証と ID Token の auth_time に使う。
	AuthenticatedAt time.Time
	// GrantedScopes は要求 scope の部分集合。
	GrantedScopes []string
	// AMR / ACR は ID Token にそのまま載せる(OIDC Core §2)。
	AMR []string
	ACR string
	// Claims は ID Token / UserInfo 用のスナップショット(ADR-0006 §3)。
	Claims map[string]any
}

Outcome は Interaction App が Complete で伝える成功結果(ADR-0003 §3 (5))。

type Patch

type Patch struct {
	Outcome         *Outcome
	Rejection       *Rejection
	ResumeTokenHash string
}

Patch は TransitionTransaction で遷移と同時に書き込む値。nil / 空のフィールドは変更しない。

type Rejection

type Rejection struct {
	// Error は RFC 6749 §4.1.2.1 / OIDC Core §3.1.2.6 のエラーコード。
	Error       string
	Description string
}

Rejection は Interaction App が Reject で伝える失敗結果。

type Request

type Request struct {
	ClientID string

	// RedirectURI は登録情報と照合済みの、実際に使う redirect URI。
	RedirectURI string
	// RedirectURIExplicit は要求に redirect_uri パラメータが含まれていたか。
	// RFC 6749 §4.1.3 により、含まれていた場合はトークン要求でも同じ値を要求する。
	RedirectURIExplicit bool

	Scopes []string
	State  string

	// PKCE(RFC 7636)。Method は常に "S256"。
	CodeChallenge       string
	CodeChallengeMethod string

	// OIDC Core §3.1.2.1。Nonce は ID Token に転記する。他はエンジンが解釈しない。
	Nonce     string
	Prompt    []string
	MaxAge    time.Duration
	HasMaxAge bool
	LoginHint string
	UILocales string
	ACRValues string

	// Resource は RFC 8707 §2.1 の resource パラメータ。Engine の設定と Client の許可範囲で
	// 検証済みで、resource.Normalize の正規形・重複なし。要求になければ空(ADR-0008 §2、§3)。
	Resource []string
}

Request は検証済みの認可要求パラメータ。 エンジンが解釈するもの(redirect_uri, scope, PKCE, nonce)と、 Interaction App へ透過するヒント(prompt, max_age, login_hint, ...)の両方を持つ。

type Service

type Service struct {
	Clients client.Resolver
	Store   Store
	Grants  grant.Store
	Clock   clock.Clock

	// Resources は認可要求の resource パラメータで指定できる Resource Server の集合(RFC 8707 §2.1)。
	// nil なら空集合で、resource 付きの要求はすべて invalid_target になる。
	Resources *resource.Set

	// Issuer は認可サーバーの識別子(RFC 8414 の issuer)。認可応答の iss に使う(RFC 9207)。
	Issuer string

	// TransactionTTL / CodeTTL は 0 なら既定値。上限の検査は Engine の設定検証で行う。
	TransactionTTL time.Duration
	CodeTTL        time.Duration
}

Service は認可エンドポイントのユースケース群。フィールドは Engine が配線する。

func (*Service) Begin

func (s *Service) Begin(ctx context.Context, params url.Values, browserBinding string) (*Transaction, error)

Begin は /authorize の要求を検証して Transaction を作る(ADR-0003 §3 (1)(2))。

browserBinding はブラウザ結合 Cookie の値(平文)。HTTP 層が既存 Cookie を読むか新規発行して渡す。 失敗は *Error で返し、Redirectable なら Client へリダイレクトして返す。

func (*Service) Complete

func (s *Service) Complete(ctx context.Context, txnID string, out Outcome) (string, error)

Complete は Interaction App からの成功結果を記録し、Resume Token の平文を返す(ADR-0003 §3 (5))。

Outcome の検証: subject 非空、authenticated_at 非ゼロ、granted_scopes が要求 scope の 空でない部分集合、max_age 要求時は認証が新しいこと。

func (*Service) Reject

func (s *Service) Reject(ctx context.Context, txnID string, rej Rejection) (string, error)

Reject は Interaction App からの失敗結果を記録し、Resume Token の平文を返す。

func (*Service) Resume

func (s *Service) Resume(ctx context.Context, txnID, resumeToken, browserBinding string) (string, error)

Resume はブラウザが Resume URL で戻ってきたときに Code を発行し、Client へのリダイレクト URL を返す (ADR-0003 §3 (7)(8))。

失敗のうち ErrTransactionNotFound / ErrTransactionExpired / ErrResumeDenied は Client へリダイレクトせずエラーページを描く。Txn が rejected なら、Client 向けの エラー応答 URL を返す(これは正常な戻り値であり err は nil)。

書き込みの順序は fail-closed にする: まず Txn を consumed に遷移させ(CAS)、その後に Grant と Code を作る。途中で失敗しても Txn は消費済みで、Code は存在しない。

func (*Service) Transaction

func (s *Service) Transaction(ctx context.Context, id string) (*Transaction, error)

Transaction は存在し期限内の Transaction を返す。Interaction App が UI を描くための GET /transactions/{id} と、Complete / Reject / Resume の前提確認に使う(ADR-0003 §3 (4))。 存在しなければ ErrTransactionNotFound、期限切れなら ErrTransactionExpired を返す。

type Status

type Status string

Status は Authorization Transaction の状態。

pending ──Complete──▶ completed ──Resume──▶ consumed
   │                      │
   └──Reject──▶ rejected ─┴──Resume──▶ consumed
const (
	StatusPending   Status = "pending"
	StatusCompleted Status = "completed"
	StatusRejected  Status = "rejected"
	StatusConsumed  Status = "consumed"
)

func (Status) CanTransitionTo

func (s Status) CanTransitionTo(to Status) bool

CanTransitionTo は状態機械上で許される遷移かを返す。 Adapter は遷移の原子性(CAS)を担い、遷移の正当性はこの関数で判定する。

type Store

type Store interface {
	// CreateTransaction は Transaction を保存する。同じ ID があれば storage.ErrAlreadyExists。
	CreateTransaction(ctx context.Context, txn *Transaction) error

	// GetTransaction は ID で Transaction を返す。なければ storage.ErrNotFound。
	GetTransaction(ctx context.Context, id string) (*Transaction, error)

	// TransitionTransaction は Status が from のときだけ to に更新し、patch を適用する(CAS)。
	// Status が from でなければ storage.ErrStateConflict、存在しなければ storage.ErrNotFound。
	// 遷移の正当性(from.CanTransitionTo(to))は呼び出し側が保証する。
	TransitionTransaction(ctx context.Context, id string, from, to Status, patch Patch) error

	// CreateAuthorizationCode は Code を保存する。同じ Hash があれば storage.ErrAlreadyExists。
	CreateAuthorizationCode(ctx context.Context, code *AuthorizationCode) error
}

Store は Authorization Transaction と Authorization Code の永続化 Port。 各メソッドは単体で原子的でなければならない(ADR-0005 §1)。

type Transaction

type Transaction struct {
	ID     string
	Status Status

	// Request は検証済みの認可要求。Interaction App はこれを参照してログイン・同意 UI を描く。
	Request Request

	// BrowserBindingHash は、/authorize でブラウザに発行した結合 Cookie 値の SHA-256。
	// Resume 時に同じブラウザからの要求であることを確認する(ADR-0003 §3)。
	BrowserBindingHash string

	// Outcome は Complete で記録される結果。Status が completed / consumed のときのみ非 nil。
	Outcome *Outcome
	// Rejection は Reject で記録される結果。Status が rejected / consumed のときのみ非 nil。
	Rejection *Rejection
	// ResumeTokenHash は Complete / Reject で発行した単回使用トークンの SHA-256。
	ResumeTokenHash string

	CreatedAt time.Time
	ExpiresAt time.Time
}

Transaction は 1 回の /authorize 要求から Code 発行(または失敗)までを表す。

func (*Transaction) Expired

func (t *Transaction) Expired(now time.Time) bool

Expired は now 時点で期限切れかを返す。

Jump to

Keyboard shortcuts

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