How the S-UI API Interface Works: Session and Token Authentication Explained

The S-UI API interface is a dual-layer HTTP system built on the Gin framework, offering session-based authentication for browser interactions and token-based authentication for programmatic access, with both layers delegating business logic to a central ApiService struct.

The alireza0/s-ui repository implements a clean, modular API architecture that separates routing, authentication, and business logic. This design allows administrators to manage Sing-box configurations through both interactive web sessions and automated scripts. Understanding how the S-UI API interface handles request routing and security is essential for extending functionality or building custom integrations.

Architecture Overview

S-UI’s HTTP API is structured around two distinct authentication handlers that share a common service layer. The architecture relies on the Gin web framework for routing and middleware management.

At bootstrap, main.go initializes the router and registers both handlers under the /api base path:

router := gin.Default()
apiGroup := router.Group("/api")
api.NewAPIHandler(apiGroup, api.NewAPIv2Handler(apiGroup))

This setup creates a clear separation between the v1 session-based handler (APIHandler) for UI interactions and the v2 token-based handler (APIv2Handler) for external automation.

API Version 1: Session-Based Authentication

The v1 handler, defined in api/apiHandler.go, manages traditional browser-based authentication using HTTP cookies. It creates an APIHandler struct and installs middleware that validates login sessions for all routes except authentication endpoints.

Middleware Implementation

The session validation middleware (lines 24-29) checks the request path and validates the session cookie:

g.Use(func(c *gin.Context) {
    path := c.Request.URL.Path
    if !strings.HasSuffix(path, "login") && !strings.HasSuffix(path, "logout") {
        checkLogin(c)      // validates the session cookie
    }
})

Routing Logic

APIHandler registers two generic catch-all routes that extract the action name from the URL:

  • POST /:postActionpostHandler
  • GET /:getActiongetHandler

Inside these handlers, a switch statement matches the action parameter against supported operations (lines 34-63 for POST, lines 66-106 for GET) and forwards requests to the corresponding ApiService methods. Unknown actions return a JSON error via common.NewError.

API Version 2: Token-Based Authentication

The v2 handler in api/apiV2Handler.go provides stateless authentication suitable for scripts and third-party integrations. Instead of cookies, it relies on a Token header and maintains an in-memory list of valid tokens.

Token Management

When initialized, NewAPIv2Handler loads existing tokens from the database via ReloadTokens (lines 22-34) and stores them in memory. The checkToken middleware (lines 12-20) intercepts every request to verify the token header against this list, aborting the request if the token is missing or expired.

Endpoint Structure

Like v1, v2 uses generic POST and GET handlers, but exposes a smaller subset of actions focused on programmatic configuration management. This restricted surface area reduces security exposure for automated access.

Core Service Layer (ApiService)

All API actions converge on the ApiService struct defined in api/apiService.go. This layer aggregates domain-specific services through struct embedding:

type ApiService struct {
    service.SettingService
    service.UserService
    service.ConfigService
    service.ClientService
    // …
}

Because services are embedded, ApiService can invoke methods directly (e.g., a.UserService.Login, a.ConfigService.GetConfig). Key methods include:

  • Login – Authenticates credentials via UserService.Login and creates a session cookie using SetLoginUser
  • Save – Persists configuration changes through SettingService.Save and returns updated partial data via LoadPartialData
  • LoadData / LoadPartialData – Retrieves full or filtered configuration by calling service methods like InboundService.GetAll and ClientService.GetAll
  • GetTokens / AddToken / DeleteToken – Manage v2 API tokens through UserService methods
  • GetSingboxConfig – Streams the current Sing-box JSON configuration as a downloadable file

This delegation pattern keeps HTTP handlers thin and business logic reusable across CLI, UI, and API contexts.

Session Management Utilities

Session handling helpers reside in api/session.go and support the v1 authentication flow. These utilities manage signed cookies containing the username and expiration timestamp:

  • SetLoginUser – Creates the session cookie
  • GetLoginUser – Retrieves the authenticated user from the cookie
  • ClearSession – Invalidates the session

The v2 handler does not use these helpers, relying entirely on the in-memory token list for stateless authentication.

Practical API Examples

The following curl commands demonstrate interaction patterns with the S-UI API interface.

Session-Based Login (v1)

Authenticate and establish a session cookie:

curl -X POST http://localhost:8080/api/login \
     -d "user=admin&pass=secret"

# → sets cookie named "sui_session"

Token Generation (v2)

First obtain the session cookie, then request a token:

COOKIE=$(curl -s -c - http://localhost:8080/api/login -d "user=admin&pass=secret" | grep s_ui_session | awk '{print $7}')

curl -X POST http://localhost:8080/api/addToken \
     -b "sui_session=${COOKIE}" \
     -d "expiry=86400&desc=automation"

# → JSON: {"token":"eyJhbGciOi..."}

Fetch Configuration with Token (v2)

Use the token to retrieve configuration data:

TOKEN=eyJhbGciOi...
curl -H "Token: ${TOKEN}" http://localhost:8080/api/load

Update Client Data (v2)

Modify client settings using token authentication:

curl -X POST http://localhost:8080/api/save \
     -H "Token: ${TOKEN}" \
     -d "object=clients&action=update&data={\"id\":\"client1\",\"address\":\"10.0.0.2\"}"

Summary

  • S-UI uses a dual-version API built on Gin, with v1 for browser sessions and v2 for programmatic access
  • Authentication differs by version: v1 relies on signed cookies via checkLogin middleware in api/apiHandler.go, while v2 uses header-based tokens verified by checkToken in api/apiV2Handler.go
  • Business logic is centralized in the ApiService struct (api/apiService.go), which embeds domain services like UserService and ConfigService
  • Session state for v1 is managed through helpers in api/session.go (SetLoginUser, GetLoginUser, ClearSession), whereas v2 maintains an in-memory token list loaded via ReloadTokens
  • Extension follows a simple pattern: add cases to the switch statements in the appropriate handler, implement logic in ApiService, and optionally create new service interfaces in the service package

Frequently Asked Questions

How do I choose between v1 and v2 of the S-UI API?

Use v1 for browser-based interactions that require persistent login sessions, as it handles cookies and session management automatically. Use v2 for automation scripts that need stateless authentication via tokens, allowing external tools to interact with the API without maintaining cookie sessions. The v2 interface exposes a smaller set of actions specifically designed for programmatic configuration management.

Where is the authentication logic implemented in the source code?

The v1 session validation resides in api/apiHandler.go within the middleware closure (lines 24-29) that calls checkLogin, which is defined in api/session.go. The v2 token verification lives in api/apiV2Handler.go within the checkToken middleware (lines 12-20). Both handlers delegate authorization checks to these middleware layers before reaching the routing logic.

Can I extend the API with custom endpoints?

Yes, extending the API requires three steps: add a new case to the postHandler or getHandler switch statement in either apiHandler.go (v1) or apiV2Handler.go (v2), implement the business logic as a method on ApiService in api/apiService.go, and if the functionality represents a new domain, create a corresponding service interface in the service package. This architecture keeps routing code thin while concentrating business logic in reusable service methods.

How does token expiration work in the v2 API?

When creating a token via AddToken, you specify an expiry duration in seconds. The token is stored in the database and loaded into memory via ReloadTokens when the handler initializes. The checkToken middleware validates each request against this in-memory list, rejecting tokens that are missing or have exceeded their expiration timestamp. Tokens persist across application restarts because they are stored in the database, but the in-memory cache requires a restart or explicit reload to recognize database changes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →