SSO

Developer's guide to building SSO solutions with Go

Srinivas Karre
CONTENTS

Why add SSO to your Go applications?

Enterprise software applications rely on Single Sign On (SSO) to improve user access, security, and user experience. From Slack to Notion, users expect seamless authentication without logging into each tool separately. Companies use credential providers like Okta and Entra ID to streamline access control and reduce password fatigue.

For Go developers, implementing SSO using OpenID Connect (OIDC) or SAML manually is complex. You have to parse XML, manage access tokens, handle sign in session logic, and debug response errors. Go’s simplicity doesn’t extend to the authentication workflow, making it tedious and error-prone.

Scalekit's Go SDK abstracts the Single Sign-On logic while giving you full control over session management and user logout. It supports any Go framework—net/http, Gin, or Fiber—letting you focus on building features, not fixing auth bugs.

What this guide covers

By the end of this guide, you’ll have a fully functional SSO login flow integrated into your Go application using Scalekit. You’ll:

  • Redirect users to their identity provider (e.g., Okta or Entra ID)
  • Handle authentication callbacks and extract user identity details
  • Set secure session cookies using idTokens
  • Authenticate API requests with accessTokens
  • Test the whole flow locally using a built-in IdP simulator

The old way: Building SSO in Go manually

Example: Gatekeeper’s login failures

Gatekeeper, a fictional project management SaaS, faced a major roadblock while integrating SSO for its enterprise clients. Their engineering team initially chose to implement SSO manually using SAML libraries in Go, believing it would offer greater flexibility. However, the process quickly became overwhelming. 

Each client used a different IdP—Okta, Entra ID, and others—forcing the team to maintain multiple, complex configuration files. The token validation logic varied across providers, requiring constant adjustments to authentication flows.

Their engineering team initially wrote custom SAML authentication for each client, leading to:

  • Multiple IdP configurations: Each customer used a different identity provider (IdP like Okta, Entra ID, etc.), requiring separate XML-based configs.
  • Custom token parsing: Manually verifying SAML assertions and OAuth tokens increased complexity.
  • Inconsistent login flow: Each IdP had its own quirks, leading to broken authentication flows.

If GateKeeper had implemented SSO with Scalekit, they could have avoided the above complexities and saved days of engineering bandwidth. Let's take a look at how Scalekit makes this possible.

How Scalekit works behind the scenes

Scalekit streamlines SSO authentication in Go by handling the entire authentication lifecycle, so you don’t have to deal with protocol intricacies. Here’s how it works:

  • Abstracts SAML and OIDC complexity: No need to parse SAML assertions or manually handle OAuth token exchanges
  • Handles IdP redirections: Users are seamlessly redirected to their assigned IdP for authentication
  • Fetches user identity details: Once authenticated, Scalekit returns user attributes (e.g. email, roles) without extra processing
  • Works with any Go framework: Supports net/http, Gin, Echo and others, making integration flexible
  • Includes an IdP simulator: Simulate SSO flows locally before connecting a real enterprise IdP

End-to-end flow

Here’s what the full SSO flow looks like using Scalekit in a Go application:

  1. A user clicks “Login with SSO”
  2. Your app generates a redirect URL using Scalekit’s SDK
  3. Scalekit sends the user to their IdP (Okta, Entra ID, etc.)
  4. After login, the IdP redirects back to your app with an authorization code
  5. Your app exchanges the code for user identity details (e.g., email, roles)
  6. You establish a secure session and use the access token for authenticated API calls
Sample SSO login screen

Setting up SSO with Go

Let’s dive into the implementation. Follow along with the source code while ensuring your Scalekit dashboard is properly set up with test credentials and a redirect URI for authentication.

Before you start

Before implementing SSO in your Go app, make sure to:

  • Sign up on Scalekit and access the Dashboard
  • Register your app’s redirect URI under API Config
  • Copy your Environment URL, Client ID, and Client Secret

You’ll use these values when initializing the SDK.

1. Install the Go SDK

First, install the Scalekit SDK for Go by running:

go get -u github.com/scalekit-inc/scalekit-sdk-go

This package simplifies handling SAML and OIDC authentication flows without manually dealing with tokens, assertions, or protocol intricacies.

2. Set environment variables

Configure your application with the necessary credentials:

SCALEKIT_ENVIRONMENT_URL=your_env_url SCALEKIT_CLIENT_ID=your_client_id SCALEKIT_CLIENT_SECRET=your_client_secret

These values are obtained from your Scalekit dashboard and are crucial for securely connecting to the authentication service.

3. Initialize the Scalekit client

Set up the Scalekit client in your Go application. This client interacts with the authentication service.

package main import ( "fmt" "log" "net/http" "os" "github.com/scalekit-inc/scalekit-sdk-go" ) // Declare a global Scalekit client var client *scalekit.ScalekitClient // Initialize the Scalekit client with environment variables func init() { envUrl := os.Getenv("SCALEKIT_ENVIRONMENT_URL") // Scalekit API URL clientId := os.Getenv("SCALEKIT_CLIENT_ID")     // Your Scalekit Client ID clientSecret := os.Getenv("SCALEKIT_CLIENT_SECRET") // Your Scalekit Client Secret // Create a new Scalekit client instance client = scalekit.NewScalekitClient(envUrl, clientId, clientSecret) }

This code sets up a global Scalekit client. It reads authentication credentials from environment variables.

4. Generate the authorization URL

When a user clicks "Login with SSO," your app generates an authorization URL. This URL redirects the user to their IdP.

func loginHandler(w http.ResponseWriter, r *http.Request) { // Define the redirect URI (this should match what is set in Scalekit) redirectUri := "https://yourapp.com/callback" // Configure authorization options (e.g., specify connection ID) options := scalekit.AuthorizationUrlOptions{ ConnectionId: "conn_123456789", // Or use Org ID / Login Hint } // Generate the authorization URL using the Scalekit client authURL := client.GetAuthorizationUrl(redirectUri, options) // Redirect the user to their IdP's login page http.Redirect(w, r, authURL, http.StatusFound) }

5. Redirect users to the IdP

Attach this route to your Go web server. When users visit /login, they are redirected to their IdP.

func main() { http.HandleFunc("/login", loginHandler) // Route for SSO login log.Println("Server started on :8080") http.ListenAndServe(":8080", nil) // Start the HTTP server }

When a user accesses /login, the app redirects them to Okta, OneLogin, Entra, or another configured IdP.

6. Process the Callback Request

After authentication, the IdP redirects the user back to your app. The app receives an authorization code. It exchanges this code for user profile details.

func callbackHandler(w http.ResponseWriter, r *http.Request) { // Define the same redirect URI used during login redirectUri := "https://yourapp.com/callback" // Extract the authorization code from the URL query parameters code := r.URL.Query().Get("code") if code == "" { http.Error(w, "Authorization code missing", http.StatusBadRequest) return } // Exchange the authorization code for user profile details result, err := client.AuthenticateWithCode(code, redirectUri) if err != nil { http.Error(w, "Authentication failed", http.StatusUnauthorized) return } // Extract user email from authentication response email := result.User.Email fmt.Fprintf(w, "Welcome, %s!", email) // TODO: Securely store user session (next section) }

7. Test without a real IdP

Scalekit provides an IdP Simulator for testing. Instead of configuring a real Identity Provider, use a test email like: user@example.org

This allows you to simulate authentication flows during development.

Managing sessions in Go

Once authentication succeeds, you need to manage user sessions securely. Never store tokens in local storage, as it exposes them to cross-site scripting (XSS) attacks.

1. Store idToken securely

Use an encrypted cookie for authentication tokens. Set HttpOnly and Secure flags to prevent JavaScript access.

Example: Storing idToken in a secure cookie

import ( "net/http" "time" ) // Function to create a secure session cookie func setSessionCookie(w http.ResponseWriter, idToken string) { cookie := http.Cookie { Name:"id_token", // Cookie name Value:idToken, // Token value HttpOnly:true, // Prevents JavaScript access (XSS protection) Secure:true, // Only send over HTTPS SameSite:http.SameSiteStrictMode, // Prevents CSRF attacks Path:"/", // Accessible across the app Expires:time.Now().Add(24 * time.Hour), // Expiration time (1 day) } // Set cookie in the HTTP response http.SetCookie(w, &cookie) }

2. Use accessToken for Future API Calls

After login, use the accessToken when making authenticated API requests. Never store it on the frontend. Always pass it securely in the Authorization header.

Example: Making an authenticated API call

import ( "fmt" "net/http" ) // Function to fetch user profile with accessToken func fetchUserProfile(accessToken string) { // Create a new HTTP request to a protected API endpoint req,_ := http.NewRequest("GET", "https://yourapi.com/user", nil) // Set Authorization header with the Bearer token req.Header.Set("Authorization", "Bearer "+accessToken) // Execute the request client := &http.Client{} resp, err := client.Do(req) if err != nil { fmt.Println("API request failed:", err) return } defer resp.Body.Close() // TODO: Parse response and use user profile data}

Best practices for secure Go SSO

Security is crucial in SSO implementations. Follow these best practices to ensure a smooth implementation:

  1. Enforce HTTPS on login and callback routes to prevent MITM (Man-in-the-middle) attacks
  2. Rotate client secrets periodically to mitigate credential leaks
  3. Enable MFA (Multi-Factor Authentication) at the IdP level to add an extra layer of security
  4. Validate redirect URIs and state parameters to prevent OAuth CSRF attacks
  5. Log login attempts and token exchanges to detect suspicious activity

Wrapping up

Scalekit simplifies SSO authentication in Go by handling complex SAML/OIDC flows in just a few API calls. No more manual token parsing or XML configs. Works with any Go framework: net/http, Echo, Fiber. Test locally with @example.org, then go live with Okta, Entra, or JumpCloud.

With these best practices and Scalekit’s SDK, you can ship enterprise-ready SSO authentication in minutes

Frequently Asked Questions

Can I use Scalekit SSO with Gin or Echo in Go?

Yes, Scalekit’s Go SDK works with any Go framework including net/http, Gin, Echo, and Fiber. You just need to handle the auth endpoints and callback using your framework’s routing system.

How do I store sessions in a Go app after login?

Use the returned idToken to establish a session. Store it in an HttpOnly, Secure cookie, or in a session store like Redis. Avoid storing tokens in localStorage to reduce XSS risks.

What if I have multiple customers using different IdPs?

Scalekit supports multiple Identity Providers. You can pass a connectionId, organizationId, or loginHint (like an email) to route each login to the correct IdP.

Can I enable Social Login in my Go app with Scalekit?

Yes. Alongside enterprise SSO, Scalekit supports Social Login (Google, Microsoft, GitHub, etc.). Use the provider field when generating the authorization URL.

No items found.
Ship Enterprise Auth in days

Acquire enterprise customers with zero upfront cost

Every feature unlocked. No hidden fees.
Start Free
$0
/ month
3 FREE SSO/SCIM connections
Built-in multi-tenancy and organizations
SAML, OIDC based SSO
SCIM provisioning for users, groups
Unlimited users
Unlimited social logins