Claude
Skills
Sign in
Back

go-jwt-middleware

Included with Lifetime
$97 forever

Use when securing Go HTTP API endpoints with JWT Bearer token validation, scope/permission checks, or stateless auth. Integrates github.com/auth0/go-jwt-middleware/v3 for REST APIs receiving access tokens from frontends or mobile apps. Also handles DPoP proof-of-possession token binding. Triggers on jwtmiddleware, go-jwt-middleware, Go API auth, JWT validation, CheckJWT.

Backend & APIs

What this skill does


# Go JWT Middleware Integration

Protect Go HTTP API endpoints with JWT access token validation using github.com/auth0/go-jwt-middleware/v3.

> **Agent instruction:** Before providing SDK setup instructions, fetch the latest release version by running:
> ```bash
> gh api repos/auth0/go-jwt-middleware/releases/latest --jq '.tag_name'
> ```
> Use the returned version in all dependency lines instead of any hardcoded version below.

---

## Prerequisites

- Go 1.21 or higher
- Auth0 API configured (not Application - must be API resource)
- If you don't have Auth0 set up yet, use the `auth0-quickstart` skill first

## When NOT to Use

- **Go server-rendered web applications** - Use `go-auth0` for session-based web apps
- **Single Page Applications** - Use `auth0-react`, `auth0-vue`, or `auth0-angular` for client-side auth
- **Mobile applications** - Use `auth0-swift`, `auth0-android`, or `auth0-react-native`
- **Non-Go backends** - Use `auth0-aspnetcore-api` for .NET, `express-jwt` for Node.js

---

## Quick Start Workflow

### 1. Install SDK

```bash
go get github.com/auth0/go-jwt-middleware/v3
go get github.com/joho/godotenv
```

### 2. Create Auth0 API

You need an **API** (not Application) in Auth0.

> **Agent instruction:** If the user's prompt already provides Auth0 credentials (domain and audience), use them directly — skip the setup choice question below and proceed to Step 3 to write the `.env` file.
>
> **STOP — ask the user before proceeding.**
>
> Ask exactly this question and wait for their answer before doing anything else:
>
> > "How would you like to create the Auth0 API resource?
> > 1. **Automated** — I'll use the Auth0 CLI to create the API resource and write the exact values to your .env file automatically.
> > 2. **Manual** — You create the API yourself in the Auth0 Dashboard (or via `auth0 apis create`) and provide me the Domain and Audience.
> >
> > Which do you prefer? (1 = Automated / 2 = Manual)"
>
> Do NOT proceed to any setup steps until the user has answered. Do NOT default to manual.

**If the user chose Automated**, follow the [Setup Guide](references/setup.md) for the "Initial Setup" section (steps 1–6). The automated path writes `.env` for you — skip Step 3 below and proceed directly to Step 4.

> **Agent instruction (Automated path checkpoints):**
>
> When following the automated path, you MUST complete these checkpoints in order. Do NOT skip any:
>
> 1. **Check Auth0 CLI** — verify `auth0` is installed.
> 2. **Check Auth0 login** — run `auth0 tenants list` to verify authentication.
> 3. **Confirm active tenant** — show the user which tenant is active and ask: _"Your active Auth0 tenant is `<domain>`. Is this the correct tenant?"_ Wait for confirmation. If they say no, ask them to run `auth0 tenants use <tenant>` in their terminal.
> 4. **Ask about API name and identifier** — use `AskUserQuestion`: _"What would you like to name your Auth0 API, and what identifier (audience) should it use? For example: Name: 'My Go API', Identifier: 'https://my-api.example.com'. The identifier is a logical URI that doesn't need to resolve — it just uniquely identifies your API."_ Wait for answer. If the user is unsure, suggest deriving the identifier from the project's module name in go.mod (e.g., `https://<module-name>`).
> 5. **Ask about scopes** — use `AskUserQuestion`: _"What scopes (permissions) does your API need? For example: `read:users`, `write:users`, `read:products`. If you're not sure yet, I can start with common defaults and you can add more later."_ Wait for answer.
> 6. **Check for existing API** — run `auth0 apis list` and check if an API with the intended identifier already exists. If it does, ask the user whether to reuse it or create a new one with a different identifier.
> 7. **Create the API resource** — using the name, identifier, and scopes from steps 4–5.
> 8. **Handle .env** — if a `.env` file already exists, ask before modifying it. Never read existing `.env` contents (may contain secrets). If no `.env` exists, write one with `AUTH0_DOMAIN` and `AUTH0_AUDIENCE`.
> 9. **Add `.env` to `.gitignore`** — if not already present.
> 10. **Proceed to code integration** — skip Step 3 (already done) and go directly to Step 4 to write the middleware code.

**If the user chose Manual**, follow the [Setup Guide](references/setup.md) (Manual Setup section) for full instructions. Then continue with Step 3 below.

Quick reference for manual API creation:

```bash
# Using Auth0 CLI
auth0 apis create \
  --name "My Go API" \
  --identifier https://my-api.example.com
```

Or create manually in Auth0 Dashboard → Applications → APIs

### 3. Configure .env

```env
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_AUDIENCE=https://my-api.example.com
```

**Important:** Domain must NOT include `https://`. The middleware constructs the issuer URL automatically.

### 4. Configure main.go

> **Agent instruction (integrating with existing code):**
>
> Before writing code, determine whether you are:
> - **A) Adding auth to an existing project** — the user already has a `main.go` with routes defined. In this case, do NOT replace their file with the template below. Instead:
>   1. Add the necessary imports (`jwtmiddleware`, `jwks`, `validator`, `godotenv`, `net/url`, `os`, `context`, `strings`).
>   2. Add the `CustomClaims` struct and methods.
>   3. Add the middleware setup code (issuer URL, JWKS provider, validator, middleware) near the top of `main()`.
>   4. Ask which endpoints to protect (see below).
>   5. Wrap the specified handlers with `middleware.CheckJWT()`.
>
> - **B) Creating a new project from scratch** — use the full template below as a starting point.
>
> **STOP — ask which endpoints to protect:**
>
> If the user's request does NOT explicitly specify which endpoints to protect, ask:
>
> > "Which endpoints should require authentication? For example:
> > - **All except health/public** — protect everything, leave only specific public routes open
> > - **Specific routes** — tell me which routes need auth
> >
> > Also, do any endpoints need specific scope/permission checks (e.g., `write:users` for POST/DELETE), or is a valid JWT sufficient for all?"
>
> Wait for the answer. If the user says "all" or "everything except health", protect all routes except `/health` (or whatever they specify as public). If they specify scope requirements per endpoint, implement per-route scope checks using `customClaims.HasScope()`.

```go
package main

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"

	jwtmiddleware "github.com/auth0/go-jwt-middleware/v3"
	"github.com/auth0/go-jwt-middleware/v3/jwks"
	"github.com/auth0/go-jwt-middleware/v3/validator"
	"github.com/joho/godotenv"
)

// CustomClaims contains custom data we want from the token.
type CustomClaims struct {
	Scope       string   `json:"scope"`
	Permissions []string `json:"permissions"`
}

func (c CustomClaims) Validate(ctx context.Context) error {
	return nil
}

func (c CustomClaims) HasScope(expectedScope string) bool {
	for _, scope := range strings.Split(c.Scope, " ") {
		if scope == expectedScope {
			return true
		}
	}
	return false
}

func main() {
	if err := godotenv.Load(); err != nil {
		log.Fatalf("Error loading .env file: %v", err)
	}

	issuerURL, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/")
	if err != nil {
		log.Fatalf("Failed to parse issuer URL: %v", err)
	}

	provider, err := jwks.NewCachingProvider(
		jwks.WithIssuerURL(issuerURL),
	)
	if err != nil {
		log.Fatalf("Failed to set up JWKS provider: %v", err)
	}

	jwtValidator, err := validator.New(
		validator.WithKeyFunc(provider.KeyFunc),
		validator.WithAlgorithm(validator.RS256),
		validator.WithIssuer(issuerURL.String()),
		validator.WithAudience(os.Getenv("AUTH0_AUDIENCE")),
		validator.WithCustomClaims(func() validator.CustomClaims {
			return &CustomClaims{}
		}),
	)
	if err != nil {
		log.Fatalf("Failed to set up JWT validator: %v", err)
	}

	middleware, err := jwtmiddlewar

Related in Backend & APIs