Protect Backend Endpoints

Learn how the auth middleware can be used to protect authenticated APIs.

Secure application endpoints by utilizing the app.RequireAuthentication middleware chain to ensure access is restricted to authenticated users. This approach effectively protects routes, requiring authentication for user access.

Using the Auth Middleware to Protect Endpoints

Use the following auth middleware chain to restrict access to authenticated users:

// Auth middleware chain configured in "main.go":
// authMiddlewares := goauth.Middlewares{
//   app.RequireAuthentication
// }

// Protected endpoint handler
protectedHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(`{"message": "This is a protected route"}`))
})

// Apply middleware to the registered protected endpoint
http.Handle("/api/protected", authMiddlewares.Apply(protectedHandler))

Requests without a valid session will automatically receive a 401 Unauthorized error.


Accessing Session Data in Protected Handlers

The middleware automatically includes the session in the request context. Retrieve it using goauth.SessionFromContext:

Accessing Session in Handler

func protectedHandler(w http.ResponseWriter, r *http.Request) {
    session := goauth.SessionFromContext(r.Context())
    if session == nil {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }

    // Access session data
    userID := session.UserInfo.Sub
    tenantID := session.TenantID
    accessToken := session.AccessToken

    // Use the access token for downstream API calls
    response := map[string]string{
        "userId":   userID,
        "tenantId": tenantID,
        "message":  "Hello from protected endpoint",
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(response)
}

Handling 401 Responses in Frontend Code

Frontend requests to protected APIs may receive the following error response:

  • 401 Unauthorized: This response will be returned if the session is missing or invalid.

To maintain a smooth user experience, your frontend must handle this error properly. Review these common JavaScript patterns for managing 401 responses.

Pattern 1: Use an Axios Interceptor

For Axios users, a response interceptor can automatically redirect users to the login endpoint upon encountering a 401 error.

// api-client.ts
import axios from 'axios';
import { redirectToLogin } from '@wristband/react-client-auth';

const apiClient = axios.create({
  baseURL: '<backend-apis-base-url>',
  headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
  withCredentials: true,
});

// If a 401 response is detected, redirect the user to your Login Endpoint.
const unauthorizedAccessInterceptor = (error: unknown) => {
  if (axios.isAxiosError(error) && error.response?.status === 401) {
    redirectToLogin('<your-login-endpoint-url>');
    return;
  }
  return Promise.reject(error);
};

apiClient.interceptors.response.use(undefined, unauthorizedAccessInterceptor);

export { apiClient };

Pattern 2: Explicitly Catch Errors When Making API Calls

Catch 401 errors explicitly on individual backend API calls to implement targeted, request-specific error handling.

import axios from 'axios';
import { redirectToLogin } from '@wristband/react-client-auth';

async function executeApiCall() {
  try {
    const response = await axios.get('<your-server-api-url>');
    alert('Success!');
  } catch (error: unknown) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      redirectToLogin('<your-login-endpoint-url>');
    } else {
      console.error('Unexpected error:', error);
      alert('Something went wrong!');
    }
  }
}
import { redirectToLogin } from '@wristband/react-client-auth';

function getCookie(name: string): string | null {
  const match = document.cookie.match(new RegExp('(^|;\\s*)' + name + '=([^;]*)'));
  return match ? decodeURIComponent(match[2]) : null;
}

async function executeApiCall() {
  const csrfToken = getCookie('CSRF-TOKEN');

  try {
    const response = await fetch('/api/protected-endpoint', {
      credentials: 'include',
      headers: {
        'X-CSRF-TOKEN': csrfToken ?? ''
      }
    });

    if (!response.ok) {
      if (response.status === 401 || response.status === 403) {
        redirectToLogin('<your-login-endpoint-url>');
        return;
      }

      const errorText = await response.text();
      throw new Error(`HTTP error! status: ${response.status}, Message: ${errorText}`);
    }

    ...
  } catch (error) {
    ...
  }
}

What’s Next

Now that you've finished protecting your backend endpoints, let's run some final tests to ensure everything is working.

Did this page help you?