Skip to Content
Clerk logo

Clerk Docs

Ctrl + K
Go to clerkstage.dev

Verify a Clerk session in Go

There are two ways to verify a session with Clerk in your Go application:

  • Using Clerk middleware
    If you want to verify a session in an HTTP context, it is recommended to use Clerk middleware. Clerk middleware guarantees better performance and efficiency by making the minimum necessary requests to the Clerk Backend API.

  • Manually verifying the session token
    If you want to verify a session in a non-HTTP context, or if you would like total control over the verification process, you can verify the session token on your own.

Use Clerk middleware to verify a session

Go enables you to create a simple HTTP server, and Clerk enables you to authenticate any request. Together, you can create a secure server that only allows authenticated users to access certain routes.

Clerk Go SDK provides two functions for adding authentication to HTTP handlers:

Both middleware functions support header based authentication with a bearer token. The token will be parsed, verified, and its claims will be extracted as SessionClaims(opens in a new tab).

The claims will then be made available in the http.Request.Context for the next handler in the chain. Clerk Go SDK provides the SessionClaimsFromContext()(opens in a new tab) helper for accessing the claims from the context.

The following example demonstrates how to use the WithHeaderAuthorization() middleware to protect a route. If the user tries accessing the route and their session token is valid, the user's ID will be returned in the response.

Your Clerk secret key is required. If you are signed in to your Clerk Dashboard, your secret key should become visible by selecting the eye icon. Otherwise, you can retrieve your Clerk secret key from the Clerk Dashboard on the API Keys(opens in a new tab) page.

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

Manually verify a session token

Verifying a Clerk session manually is useful when you want to verify a session in a non-HTTP context, or if you would like total control over the verification process. With the solution above, Clerk middleware makes the minimum necessary requests to the Clerk Backend API. With this solution, you must be mindful of API rate limits.

Verifying a session token requires providing a JSON Web Key. When using Clerk middleware to verify a session, it fetches the JSON Web Key once and caches it for you. However, when manually verifying a session, you are required to fetch and cache the JSON Web Key yourself.

Clerk Go SDK provides a set of functions for decoding and verifying JWTs, as well as fetching JSON Web Key Sets. It is recommended to cache your JSON Web Key and invalidate the cache only when a replacement key is generated.

The following example demonstrates how to manually verify a session token. If the user tries accessing the route and their session token is valid, the user's ID will be returned in the response.

import ( "fmt" "net/http" "github.com/clerk/clerk-sdk-go/v2" "github.com/clerk/clerk-sdk-go/v2/jwks" "github.com/clerk/clerk-sdk-go/v2/jwt" ) func main() { clerk.SetKey(`{{secret}}`) mux := http.NewServeMux() mux.HandleFunc("/", publicRoute) // Fetch the JSON Web Key Set. // Make sure you refetch the JSON Web Key Set whenever your // Clerk secret key changes. jwks, err := jwks.Get(context.Background() &jwks.GetParams{}) if err != nil { panic(err) } mux.Handle("/protected", protectedRoute(jwks)), http.ListenAndServe(":3000", mux) } func publicRoute(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"access": "public"}`)) } func protectedRoute(jwks *clerk.JSONWebKeySet) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { // Get the session JWT from the Authorization header sessionToken := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") unsafeClaims, err := jwt.Decode(r.Context(), &jwt.DecodeParams{ Token: sessionToken, }) if err != nil { // handle the error w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(`{"access": "unauthorized"}`)) return } // Fetch the correct JSON Web Key var jwk *clerk.JSONWebKey for _, k := range jwks.Keys { if k.KeyID == unsafeClaims.KeyID { jwk = k break } } if jwk == nil { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(`{"access": "unauthorized"}`)) return } // Verify the session claims, err := jwt.Verify(r.Context(), &jwt.VerifyParams{ Token: sessionToken, JWK: jwk, }) if err != nil { // handle the error w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(`{"access": "unauthorized"}`)) return } fmt.Fprintf(w, `{"user_id": "%s"}`, claims.Subject) } }

What did you think of this content?

Clerk © 2024