Testing Authenticated API Endpoints with Go

Testing Authenticated Endpoints

Welcome to the final lesson in our journey through automated API testing with Go. In this lesson, we'll focus on testing authenticated API endpoints. While you've already learned to organize tests and handle CRUD operations using Go's testing package, today we'll delve into how APIs manage secure access through different authentication methods — API Keys, Sessions, and JWT (JSON Web Tokens).

Authentication is crucial for securing API endpoints against unauthorized access. By understanding how to test these mechanisms, you'll ensure that your API maintains its integrity and protects sensitive data. We'll explore practical examples for each authentication method, giving you the tools to verify that only authorized users can interact with protected resources.

API Key Authentication

API Key authentication is one of the simplest ways to secure an API. It involves sending a unique key as part of the request headers, allowing access to protected endpoints. Let's look at an example of how you can set up and test API Key authentication using Go's HTTP client and testing packages:

package main_test

import (
    "net/http"
    "testing"
)

const (
    baseURL = "http://localhost:8000"
    apiKey  = "123e4567-e89b-12d3-a456-426614174000"
)

func TestAPIKeyAuthentication(t *testing.T) {
    // Arrange
    req, err := http.NewRequest("GET", baseURL+"/todos", nil)
    if err != nil {
        t.Fatal(err)
    }
    req.Header.Set("X-API-Key", apiKey)

    client := &http.Client{}

    // Act
    resp, err := client.Do(req)
    if err != nil {
        t.Fatal(err)
    }
    defer resp.Body.Close()

    // Assert
    if resp.StatusCode != http.StatusOK {
        t.Errorf("Expected status 200, got %v", resp.StatusCode)
    }
}

Here, we define a test function TestAPIKeyAuthentication. We create a new HTTP request and set the X-API-Key header. We then use an http.Client{} to send the request and verify that the response status code is 200, indicating successful authentication and access to the endpoint.

Session Authentication: Setup

In Go, managing sessions involves maintaining state across requests. We'll set up a helper function to handle login and maintain session state, enabling each test to authenticate independently:

package main_test

import (
    "bytes"
    "encoding/json"
    "net/http"
    "net/http/cookiejar"
    "testing"
)

type AuthDetails struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

func login(t *testing.T, authDetails AuthDetails) *http.Client {
    jar, _ := cookiejar.New(nil)
    client := &http.Client{Jar: jar}
    data, _ := json.Marshal(authDetails)
    req, err := http.NewRequest("POST", baseURL+"/auth/login", bytes.NewBuffer(data))
    if err != nil {
        t.Fatal(err)
    }
    req.Header.Set("Content-Type", "application/json")

    resp, err := client.Do(req)
    if err != nil {
        t.Fatal(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        t.Fatalf("Expected status 200, got %v", resp.StatusCode)
    }

    return client
}

The login function sends a login request and returns an HTTP client that maintains session state.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal