Clerk Go SDK

repository·v2·Indexed 41 days ago

https://github.com/clerk/clerk-sdk-go

The official client library for interacting with the Clerk Backend API using Go. The SDK allows developers to manage authentication, users, and other Clerk resources. It features support for both global package-level functions and client-based configurations for multi-tenant environments, as well as built-in middleware for bearer token authentication in HTTP servers. Version v2 requires Go 1.24 or later.

Tokens
64.8K
Snippets
291
Records
314
Agent score
96%

What's inside Clerk

  1. Access API response metadata

    v2

    Every resource returned by a Clerk API operation includes a Response field of type APIResponse. This field allows you to inspect metadata from the Clerk Backend API, such as HTTP headers, status, and the raw response body. You can use the Success() method to check if the operation was successful.

    dmn, err := domain.Create(context.Background(), &domain.CreateParams{})
    if err != nil {
        // handle error
    }
    if !dmn.Response.Success() {
        fmt.Println(dmn.Response.TraceID)
    }
  2. Handle list operation responses in v2

    v2

    List operations in v2 return a response object that consistently contains:

    1. A TotalCount field (the total number of resources available on the server).
    2. A slice of the resource type (e.g., Users, Organizations) containing the results for the current request.
    // Example for the 'user' resource
    list, err := user.List(ctx, &user.ListParams{})
    // list.TotalCount contains the total count
    // list.Users contains the slice of users
  3. Use the Clerk Go SDK with a client

    v2

    If your application needs to manage multiple Clerk API keys (e.g., in a multi-tenant environment), use the client-based approach. Each resource package exports a NewClient function that returns a client instance configured with a specific key.

    To use this pattern:

    1. Import the core github.com/clerk/clerk-sdk-go/v2 package and the specific resource package.
    2. Create a clerk.ClientConfig and set the Key.
    3. Initialize the client using resource.NewClient(config).
    4. Call operations directly on the client instance (e.g., client.Get(...)).
    import (
        "github.com/clerk/clerk-sdk-go/v2"
        "github.com/clerk/clerk-sdk-go/v2/organization"
    )
    
    ctx := context.Background()
    config := &clerk.ClientConfig{}
    config.Key = clerk.String("sk_live_XXX")
    client := organization.NewClient(config)
    
    // Create
    org, err := client.Create(ctx, &organization.CreateParams{Name: clerk.String("Clerk Inc")})
  4. Mock the Clerk SDK for testing

    v2

    Depending on whether you use the global API or the client-based API, there are different ways to mock requests in your tests.

    If using the Global API (without client)

    1. Custom Transport: Use clerk.SetBackend with a clerk.NewBackend containing a custom http.Client.Transport (implementing http.RoundTripper).
    2. httptest Server: Use clerk.SetBackend with a clerk.NewBackend configured with the URL and Client from an httptest.Server.
    3. Custom Backend: Implement the clerk.Backend interface and set it via clerk.SetBackend(&myCustomBackend{}).

    If using the Client-based API

    1. Custom Transport: Pass a clerk.ClientConfig with a custom HTTPClient (containing a mock Transport) to resource.NewClient(config).
    2. httptest Server: Pass a clerk.ClientConfig with the HTTPClient and URL from an httptest.Server to resource.NewClient(config).
    3. Custom Backend: Assign a custom implementation of the clerk.Backend interface directly to the client instance: client.Backend = &myCustomBackend{}.
    // Example: Mocking with a custom transport in a client-based approach
    func TestWithCustomTransport(t *testing.T) {
        config := &clerk.ClientConfig{}
        config.HTTPClient = &http.Client{
            Transport: &mockRoundTripper{},
        }
        client := user.NewClient(config)
        client.Get(context.Background(), "user_id")
    }
    
    type mockRoundTripper struct {}
    func (m *mockRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
        return &http.Response{}, nil
    }
  5. Implement HTTP middleware for bearer token authentication

    v2

    The v2 library provides middleware in the github.com/clerk/clerk-sdk-go/v2/http package. Note that these only support bearer tokens in the Authorization header; cookie-based authentication is not supported.

    Basic Usage

    Use clerkhttp.RequireHeaderAuthorization() to protect routes. Access session information in your handlers using clerk.SessionClaimsFromContext(r.Context()).

    Using a JWKS Client

    If managing multiple API keys, you can pass a jwks.Client to the middleware:

    import (
        "net/http"
        "github.com/clerk/clerk-sdk-go/v2"
        clerkhttp "github.com/clerk/clerk-sdk-go/v2/http"
        "github.com/clerk/clerk-sdk-go/v2/jwks"
    )
    
    func main() {
        config := &clerk.ClientConfig{}
        config.Key = "sk_live_XXX"
        client := jwks.NewClient(config)
        
        mux := http.NewServeMux()
        withAuth := clerkhttp.RequireHeaderAuthorization(
            clerkhttp.JWKSClient(client),
        )
        mux.Handle("/session", withAuth(http.HandlerFunc(handleSession)))
        http.ListenAndServe(":3000", mux)
    }
    import (
        "net/http"
        "github.com/clerk/clerk-sdk-go/v2"
        clerkhttp "github.com/clerk/clerk-sdk-go/v2/http"
        "github.com/clerk/clerk-sdk-go/v2/jwks"
    )
    
    func main() {
        config := &clerk.ClientConfig{}
        config.Key = "sk_live_XXX"
        client := jwks.NewClient(config)
        mux := http.NewServeMux()
        withAuth := clerkhttp.RequireHeaderAuthorization(
            clerkhttp.JWKSClient(client),
        )
        mux.Handle("/session", withAuth(http.HandlerFunc(handleSession)))
        http.ListenAndServe(":3000", mux)
    }
  6. Use the Clerk Go SDK without a client

    v2

    If your application only uses a single Clerk API key, you can use the global package-level functions. This is the recommended approach for most simple use cases.

    To use this pattern:

    1. Import the core github.com/clerk/clerk-sdk-go/v2 package and the specific resource package (e.g., github.com/clerk/clerk-sdk-go/v2/user).
    2. Call clerk.SetKey("your_api_key") to configure the global key.
    3. Call resource functions (like Create, Get, Update, Delete, or List) passing a context.Context as the first argument.
    import (
        "github.com/clerk/clerk-sdk-go/v2"
        "github.com/clerk/clerk-sdk-go/v2/organization"
    )
    
    ctx := context.Background()
    clerk.SetKey("sk_live_XXX")
    
    // Create an organization
    org, err := organization.Create(ctx, &organization.CreateParams{
        Name: clerk.String("Clerk Inc"),
    })
  7. Configure the Clerk API key

    v2

    You can set the Clerk API key globally at the package level using SetKey. This key will be used by the default backend if no specific key is provided in a BackendConfig.

    import "github.com/clerk/clerk-sdk-go"
    
    func main() {
        clerk.SetKey("sk_test_...")
    }
  8. Migrate from v1 to v2 of the Clerk Go SDK

    v2

    The v2 version of the Clerk Go SDK is a complete rewrite with breaking changes. Key differences include:

    • Package Layout: v1 used a single clerk.Client with service properties. v2 uses a resource-based structure where every API has its own package (e.g., github.com/clerk/clerk-sdk-go/v2/organization).
    • Authentication: v2 middleware supports only bearer tokens in the Authorization header. Cookie-based authentication is no longer supported.
    • Parameter Types: In v2, all fields in parameter structs are pointers. Use helper functions like clerk.String(), clerk.Bool(), and clerk.Int64() to pass values.
    • Minimum Requirements: Requires Go 1.19 or higher.
  9. Add Clerk authentication middleware to HTTP handlers

    v2

    The SDK provides middleware to handle bearer token authentication in Go HTTP servers. The middleware parses the token, verifies it, and extracts SessionClaims, which are then injected into the http.Request.Context().

    Available Middleware

    • WithHeaderAuthorization(): Extracts claims and makes them available in the context. If authentication fails, it does not block the request (it's up to your handler to check).
    • RequireHeaderAuthorization(): Similar to WithHeaderAuthorization, but automatically responds with HTTP 403 Forbidden if valid session claims are not detected.

    Accessing Claims

    Use clerk.SessionClaimsFromContext(r.Context()) to retrieve the claims within your handler.

    import (
    	"fmt"
    	"net/http"
    
    	"github.com/clerk/clerk-sdk-go/v2"
    	clerkhttp "github.com/clerk/clerk-sdk-go/v2/http"
    )
    
    func main() {
    	clerk.SetKey("sk_live_XXX")
    	mux := http.NewServeMux()
    	mux.HandleFunc("/", publicRoute)
    	
    	// Protect this route
    	protectedHandler := http.HandlerFunc(protectedRoute)
    	mux.Handle("/protected", clerkhttp.WithHeaderAuthorization()(protectedHandler))
    
    	http.ListenAndServe(":3000", mux)
    }
    
    func protectedRoute(w http.ResponseWriter, r *http.Request) {
    	claims, ok := clerk.SessionClaimsFromContext(r.Context())
    	if !ok {
    		w.WriteHeader(http.StatusUnauthorized)
    		return
    	}
    	fmt.Fprintf(w, "{\"user_id\": \"%s\"}", claims.Subject)
    }