Auth0 isn’t just for web apps; it’s a powerful, drop-in solution for securing your Go APIs, acting as your central authentication and authorization authority so you don’t have to build it yourself.

Let’s secure a simple Go API using Auth0. We’ll create an API endpoint that requires a valid JWT from Auth0 to access.

First, we need an Auth0 application. Log in to your Auth0 dashboard, go to "Applications," and click "Create Application." Choose "Machine to Machine Applications" and name it something like "MyGoAPI." Under "API," select "Create API" and name it "MyGoAPI" again. Grant the machine-to-machine application permission to access this API. Note down your Auth0 "Domain" and "API Audience" (this is usually the same as your API identifier, which is often the URL you set up for your API, like http://localhost:8080 or https://api.example.com).

Now, let’s set up our Go API. We’ll use the go-jwt-middleware library, which is excellent for this.

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	"github.com/auth0/go-jwt-middleware"
	"github.com/dgrijalva/jwt-go"
)

// Define your Auth0 configuration
var (
	auth0Domain   = "YOUR_AUTH0_DOMAIN.auth0.com" // e.g., "dev-abcdefg.us.auth0.com"
	auth0Audience = "YOUR_API_AUDIENCE"         // e.g., "http://localhost:8080" or your API identifier
)

func main() {
	// Create a new JWT middleware instance
	jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
			// Provide the signing key (public key) for validation
			// For Auth0, this is typically fetched from the JWKS endpoint
			// The library handles fetching and caching JWKS automatically
			return jwtmiddleware.NewGCPublicKeyFinder(auth0Domain), nil
		},
		SigningMethod: jwt.SigningMethodRS256, // Ensure this matches your Auth0 API's signing algorithm
		// You can add more options here, like looking for the token in headers,
		// query params, or cookies. The default is the Authorization header.
	})

	// Define your protected handler
	protectedHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Access claims from the token
		claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
		userID := claims["sub"].(string) // 'sub' is the standard claim for the subject (user ID)

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(map[string]string{"message": fmt.Sprintf("Hello, %s! This is a protected API.", userID)})
	})

	// Apply the JWT middleware to the protected handler
	protectedAPI := jwtMiddleware.Handler(protectedHandler)

	// Define a public handler
	publicHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(map[string]string{"message": "This is a public API."})
	})

	// Set up HTTP routes
	http.HandleFunc("/public", publicHandler)
	http.Handle("/protected", protectedAPI) // Use .Handle for middleware

	fmt.Printf("Server starting on :8080...\n")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Replace YOUR_AUTH0_DOMAIN.auth0.com and YOUR_API_AUDIENCE with your actual Auth0 domain and API audience.

To run this, you’ll need to install the libraries: go get github.com/auth0/go-jwt-middleware go get github.com/dgrijalva/jwt-go

When a request comes into /protected, the jwtMiddleware intercepts it. It looks for a JWT, typically in the Authorization: Bearer <token> header. It then uses the ValidationKeyGetter to fetch Auth0’s public keys (from their JWKS endpoint) and verifies the JWT’s signature. If the signature is valid and the token hasn’t expired, it extracts the claims and attaches them to the request’s context. Your protectedHandler can then access these claims, like the user’s subject ID (sub), to personalize responses or perform further authorization checks.

To get a token, you’d typically use an Auth0 client SDK (like auth0-go for a backend application or a frontend SDK like auth0-spa-js) to authenticate a user and request an access token for your API. This token is what your client application will send in the Authorization header.

The jwtmiddleware.NewGCPublicKeyFinder(auth0Domain) is a crucial part. It automatically handles fetching the JSON Web Key Set (JWKS) from Auth0’s /jwks/ endpoint. These public keys are used to verify that the JWT was indeed issued by Auth0 and hasn’t been tampered with. The middleware caches these keys to avoid repeatedly fetching them.

The jwt.SigningMethodRS256 specifies the algorithm used to sign the JWT. Auth0 uses RS256 by default for API access tokens, which is a robust asymmetric signing algorithm.

The most surprising thing about using Auth0 for API security is how little you actually implement yourself; the library handles the complex cryptographic verification, key rotation, and token parsing, abstracting away the intricate details of JWT validation.

When you request a token from Auth0 for your API, the token payload will contain various claims. The sub claim (subject) is a unique identifier for the authenticated user. You can also request custom claims or scopes during the token issuance process to pass specific user permissions or data to your API.

The jwtmiddleware.Options struct allows fine-grained control. For instance, you can set EnableExpirationCheck(true) (which is on by default) to ensure tokens are not used past their expiry. You can also configure CredentialsOptional(true) if you have some endpoints that don’t require authentication.

If you were to try and access /protected without a valid Authorization: Bearer <token> header, the middleware would return a 401 Unauthorized error.

The next step is often implementing role-based access control (RBAC) using the roles and permissions claims that can be configured in Auth0.

Want structured learning?

Take the full Auth0 course →