Skip to main content
skill CX Codex

encore-go-auth — Claude Code skill: setup

This skill helps secure Encore Go endpoints and identify callers. Use it for JWTs, API keys, bearer tokens, or session cookies.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add encoredev/skills --skill encore-go-auth -a claude-code
npx skills add encoredev/skills --skill go-auth -a claude-code
Open on GitHub

What encore-go-auth does

The skill explains Encore Go’s built-in authentication flow. An //encore:authhandler function receives request parameters and returns an auth.UID, auth data, and an error. It can read the Authorization header, validate a bearer token or API key, and return errs.Unauthenticated when credentials fail.

Endpoint access is declared with //encore:api auth; public routes use //encore:api public. Handler code can call auth.UserID() and auth.Data() to obtain the caller’s ID, email, and role. Authentication parameters may also come from cookies or query strings.

The handler signature is fixed: context.Context, a pointer to a parameter struct, and (auth.UID, *AuthData, error). Without //encore:authhandler, Encore will not treat the function as an authentication handler.

What it helps with

  • protect an Encore Go endpoint with authentication
  • validate a bearer token or JWT from Authorization
  • read the current caller’s ID, email, and role
  • return a 401 response for invalid credentials
  • accept authentication from a cookie or API key

Example prompts for the agent

  • Add //encore:api auth to the profile endpoint and read the caller with auth.UserID() and auth.Data().
  • Create an //encore:authhandler that validates a bearer token from Authorization and returns errs.Unauthenticated on failure.
  • Show how to authenticate an Encore Go request with a session cookie.

How to install encore-go-auth

1Skills CLI (Vercel)

npx skills add encoredev/skills --skill encore-go-auth -a claude-code
npx skills add encoredev/skills --skill go-auth -a claude-code

2Manually: put the files in place

~/.claude/skills/go-auth/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/go-auth/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about encore-go-auth

How do I install encore-go-auth in Claude Code?

Run npx skills add encoredev/skills --skill encore-go-auth -a claude-code, then run npx skills add encoredev/skills --skill go-auth -a claude-code. The skill file is available at ~/.claude/skills/go-auth/SKILL.md.

What does encore-go-auth do?

It guides Encore Go authentication setup: defining an auth.AuthHandler, securing endpoints with //encore:api auth, and reading the current user’s auth data.

What signature must an Encore auth handler use?

The function needs //encore:authhandler, accepts context.Context and a pointer to a parameter struct, and returns (auth.UID, *AuthData, error). Invalid credentials use errs.Unauthenticated.

Source text

SKILL.md · Apache-2.0
---
name: encore-go-auth
description: Protect Encore Go endpoints with authentication and authorize callers. Covers `auth.AuthHandler`, `auth.UserID`, the `Authorization` header, and `//encore:api auth`.
when_to_use: >-
  User wants to require login on a Go endpoint, restrict an endpoint to authenticated/signed-in users, validate a bearer token / JWT / API key from an `Authorization` header, read the current user inside a handler (`auth.UserID()` / `auth.Data()`), define an `auth.AuthHandler`, return `errs.Unauthenticated` from a handler, or use `//encore:api auth` on a handler. Trigger phrases: "protect this endpoint", "only authenticated users", "require login", "Authorization header", "bearer token", "401", "403", "who is calling", "current user".
---

# Encore Go Authentication

## Instructions

Encore Go provides a built-in authentication system using the `//encore:authhandler` annotation.

### 1. Create an Auth Handler

```go
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. Protect Endpoints

```go
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. Access Auth Data in Endpoints

```go
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
}
```

## Auth Handler Signature

The auth handler must:
1. Have the `//encore:authhandler` annotation
2. Accept `context.Context` and a params struct pointer
3. Return `(auth.UID, *YourAuthData, error)`

```go
//encore:authhandler
func MyAuthHandler(ctx context.Context, params *Params) (auth.UID, *AuthData, error)
```

## Auth Handler Behavior

| Scenario | Returns | Result |
|----------|---------|--------|
| Valid credentials | `(uid, data, nil)` | Request authenticated |
| Invalid credentials | `("", nil, err)` with `errs.Unauthenticated` | 401 response |
| Other error | `("", nil, err)` | Request aborted |

## Common Auth Patterns

### JWT Token Validation

```go
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 Key Authentication

```go
//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-Based Auth

```go
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
}
```

### Multi-Source Auth (Cookie + Header + Query)

Auth params can extract data from multiple sources:

```go
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",
    }
}
```

## Service-to-Service Auth

Auth data automatically propagates in internal service calls:

```go
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
}
```

## Testing with Auth

Override auth data in tests using `auth.WithContext`:

```go
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)
    }
}
```

## Guidelines

- Only one `//encore:authhandler` per application
- Return `auth.UID` as the first return value (user identifier)
- Return your custom `AuthData` struct as second value
- Use `auth.UserID()` to get the authenticated user ID
- Use `auth.Data()` and type assert to get full auth data
- Auth propagates automatically in service-to-service calls
- Use `auth.WithContext()` to override auth in tests
- Keep auth handlers fast - they run on every authenticated request

© encoredev · Apache-2.0 · encoredev/skills

Similar skills

All skills for Backend and APIs →

From the same set25

encore-database Teaches the AI agent to manage PostgreSQL in Encore.ts applications. It guides schema migrations and typed SQL queries using SQLDatabase. CX Codex +1 799installs encore-testing Guides your agent through writing and running automated tests for Encore.ts with encore test and vitest or jest. Useful when an endpoint or service needs coverage without hand-rolling test databases. CX Codex +1 791installs encore-frontend A skill that connects React, Next.js, Vue or Svelte apps to an Encore.ts backend: typed client generation, CORS setup and auth tokens. CX Codex +1 763installs encore-migrate Guides step-by-step backend migrations to Encore.ts or Encore Go. It tracks progress via migration-plan.md, separates backend APIs from frontend code, and supports an autonomous mode. CX Codex +1 725installs encore-go-testing Write and run Encore Go tests with encore test and Go’s standard testing package. It covers handlers, service calls, databases, errors, and test structure. CX Codex +1 556installs encore-go-service This skill structures Encore.go services, Go packages, systems, and typed calls between services. Use it when adding a service or applying an agreed layout. CX Codex +1 555installs encore-go-api Teaches the agent to write Encore Go endpoints with the //encore:api annotation: typed request and response structs, path, query, header and cookie params, error codes. CX Codex +1 555installs encore-go-database Guides SQL queries, schema migrations, and PostgreSQL setup in Encore Go services using the sqldb package. CX Codex +1 553installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor