encore-go-auth について
Encore Go アプリケーションで認証を実装するためのガイドです。認証ハンドラー、保護されたエンドポイント、サービス間の認証データ伝播を扱います。
主な機能
- 01認証ハンドラーと戻り値の定義
- 02API エンドポイントの保護
- 03ヘッダー、Cookie、クエリパラメーターからの認証情報取得
- 04サービス間での認証データ伝播
- 05テストでの認証データの上書き
活用シーン
- 01JWT、API キー、Cookie によるリクエスト認証
- 02プロフィールなどのエンドポイントへの認証要件の設定
- 03任意のユーザー ID を使ったエンドポイントのテスト
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ encoredev/ skills --skill encore-go-authインストール後、Claude Code で/encore-go-authを入力して読み込まれたか確認します。
詳細
Encore Go 認証
手順
Encore Go は、//encore:authhandler アノテーションを使用した組み込みの認証システムを提供します。
1. 認証ハンドラーを作成する
package auth
import (
"context"
"encore.dev/beta/auth"
"encore.dev/beta/errs"
)
// AuthParams defines what the auth handler receives
type AuthParams struct {
Authorization string `header:"Authorization"`
}
// AuthData defines what authenticated requests have access to
type AuthData struct {
UserID string
Email string
Role string
}
//encore:authhandler
func Authenticate(ctx context.Context, params *AuthParams) (auth.UID, *AuthData, error) {
token := strings.TrimPrefix(params.Authorization, "Bearer ")
payload, err := verifyToken(token)
if err != nil {
return "", nil, &errs.Error{
Code: errs.Unauthenticated,
Message: "invalid token",
}
}
return auth.UID(payload.UserID), &AuthData{
UserID: payload.UserID,
Email: payload.Email,
Role: payload.Role,
}, nil
}
2. エンドポイントを保護する
package user
import "context"
// Protected endpoint - requires authentication
//encore:api auth method=GET path=/profile
func GetProfile(ctx context.Context) (*Profile, error) {
// Only authenticated users reach here
}
// Public endpoint - no authentication required
//encore:api public method=GET path=/health
func Health(ctx context.Context) (*HealthResponse, error) {
return &HealthResponse{Status: "ok"}, nil
}
3. エンドポイントで認証データにアクセスする
package user
import (
"context"
"encore.dev/beta/auth"
myauth "myapp/auth" // Import your auth package
)
//encore:api auth method=GET path=/profile
func GetProfile(ctx context.Context) (*Profile, error) {
// Get the user ID
userID, ok := auth.UserID()
if !ok {
// Should not happen with auth endpoint
}
// Get full auth data
data := auth.Data().(*myauth.AuthData)
return &Profile{
UserID: string(userID),
Email: data.Email,
Role: data.Role,
}, nil
}
認証ハンドラーのシグネチャ
認証ハンドラーは次の条件を満たす必要があります:
//encore:authhandlerアノテーションを持つcontext.Contextと params 構造体のポインタを受け取る(auth.UID, *YourAuthData, error)を返す
//encore:authhandler
func MyAuthHandler(ctx context.Context, params *Params) (auth.UID, *AuthData, error)
認証ハンドラーの動作
| シナリオ | 戻り値 | 結果 |
|---|---|---|
| 有効な認証情報 | (uid, data, nil) | リクエストが認証される |
| 無効な認証情報 | errs.Unauthenticated を伴う ("", nil, err) | 401 レスポンス |
| その他のエラー | ("", nil, err) | リクエストが中断される |
一般的な認証パターン
JWT トークンの検証
import "github.com/golang-jwt/jwt/v5"
var secrets struct {
JWTSecret string
}
func verifyToken(tokenString string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(t *jwt.Token) (interface{}, error) {
return []byte(secrets.JWTSecret), nil
})
if err != nil {
return nil, err
}
claims, ok := token.Claims.(*Claims)
if !ok || !token.Valid {
return nil, errors.New("invalid token")
}
return claims, nil
}
API キー認証
//encore:authhandler
func Authenticate(ctx context.Context, params *AuthParams) (auth.UID, *AuthData, error) {
apiKey := params.Authorization
user, err := db.QueryRow[User](ctx, `
SELECT id, email, role FROM users WHERE api_key = $1
`, apiKey)
if err != nil {
return "", nil, &errs.Error{
Code: errs.Unauthenticated,
Message: "invalid API key",
}
}
return auth.UID(user.ID), &AuthData{
UserID: user.ID,
Email: user.Email,
Role: user.Role,
}, nil
}
Cookie ベースの認証
type AuthParams struct {
Cookie string `header:"Cookie"`
}
//encore:authhandler
func Authenticate(ctx context.Context, params *AuthParams) (auth.UID, *AuthData, error) {
sessionID := parseCookie(params.Cookie, "session")
if sessionID == "" {
return "", nil, &errs.Error{
Code: errs.Unauthenticated,
Message: "no session",
}
}
session, err := getSession(ctx, sessionID)
if err != nil || session.ExpiresAt.Before(time.Now()) {
return "", nil, &errs.Error{
Code: errs.Unauthenticated,
Message: "session expired",
}
}
return auth.UID(session.UserID), &AuthData{
UserID: session.UserID,
Email: session.Email,
Role: session.Role,
}, nil
}
マルチソース認証 (Cookie + ヘッダー + クエリ)
認証パラメータは複数のソースからデータを抽出できます:
import "net/http"
type AuthParams struct {
SessionCookie *http.Cookie `cookie:"session"` // From cookie
Authorization string `header:"Authorization"` // From header
ClientID string `query:"client_id"` // From query string
}
//encore:authhandler
func Authenticate(ctx context.Context, params *AuthParams) (auth.UID, *AuthData, error) {
// Try session cookie first
if params.SessionCookie != nil {
return authenticateWithSession(ctx, params.SessionCookie.Value)
}
// Fall back to Authorization header
if params.Authorization != "" {
return authenticateWithToken(ctx, params.Authorization)
}
return "", nil, &errs.Error{
Code: errs.Unauthenticated,
Message: "no credentials provided",
}
}
サービス間認証
認証データは内部サービス呼び出しで自動的に伝播されます:
package order
import (
"context"
"myapp/user" // Import the user service
)
//encore:api auth method=GET path=/orders/:id
func GetOrderWithUser(ctx context.Context, params *GetOrderParams) (*OrderWithUser, error) {
order, err := getOrder(ctx, params.ID)
if err != nil {
return nil, err
}
// Auth is automatically propagated to this call
profile, err := user.GetProfile(ctx)
if err != nil {
return nil, err
}
return &OrderWithUser{Order: order, User: profile}, nil
}
認証を使用したテスト
テストでは auth.WithContext を使用して認証データを上書きします:
package user_test
import (
"context"
"testing"
"encore.dev/beta/auth"
myauth "myapp/auth"
"myapp/user"
)
func TestGetProfile(t *testing.T) {
// Create a context with auth data
ctx := auth.WithContext(
context.Background(),
auth.UID("test-user-123"),
&myauth.AuthData{
UserID: "test-user-123",
Email: "[email protected]",
Role: "user",
},
)
// Call the endpoint with the authenticated context
profile, err := user.GetProfile(ctx)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if profile.Email != "[email protected]" {
t.Errorf("expected [email protected], got %s", profile.Email)
}
}
ガイドライン
- アプリケーションごとに
//encore:authhandlerは 1 つだけです - 最初の戻り値として
auth.UID(ユーザー識別子) を返します - 2 番目の値としてカスタムの
AuthData構造体を返します - 認証されたユーザー ID を取得するには
auth.UserID()を使用します - 完全な認証データを取得するには
auth.Data()を使用し、型アサーションを行います - 認証はサービス間呼び出しで自動的に伝播されます
- テストで認証を上書きするには
auth.WithContext()を使用します - 認証ハンドラーは高速に保ちます - 認証されたすべてのリクエストで実行されます
コメント
Markdown 対応