# How Pentagi Handles User Authentication and Authorization: A Deep Dive into the Go Implementation

> Discover how Pentagi secures user authentication and authorization with session login, OAuth2 SSO, and JWT tokens. Explore the Go implementation and Gin middleware in depth.

- Repository: [VXControl/pentagi](https://github.com/vxcontrol/pentagi)
- Tags: deep-dive
- Published: 2026-03-21

---

**Pentagi implements a multi-layered security model using session-based login, OAuth2 SSO (Google/GitHub), and JWT API tokens, enforced through Gin middleware that validates privileges per route.**

Pentagi, an open-source AI security automation platform developed by vxcontrol, secures its REST API and GraphQL endpoints through a comprehensive authentication and authorization pipeline. The system supports multiple identity providers and enforces fine-grained access control using privilege-based middleware in the Gin web framework.

## Session-Based Local Authentication

### Login Flow and Cookie Creation

Local users authenticate via `POST /api/v1/auth/login`, handled by the `AuthLogin` function in [`backend/pkg/server/services/auth.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/services/auth.go). The process validates the bcrypt password hash against the `users` table, verifies the account is active, and retrieves the user's privileges from the `privileges` table.

Upon successful validation, Pentagi creates a signed Gin session using `github.com/gin-contrib/sessions`:

```go
session.Set("uid", user.ID)
session.Set("uhash", user.Hash)
session.Set("rid", user.RoleID)
session.Set("tid", models.UserTypeLocal.String())
session.Set("prm", privs)               // list of strings
session.Set("gtm", time.Now().Unix())
session.Set("exp", time.Now().Add(timeout).Unix())

```

The session is persisted to an HTTP-only cookie using `auth.MakeCookieStoreKey`.

### Session Validation Middleware

Every request passes through `AuthMiddleware.tryAuth`, which invokes `tryUserCookieAuthentication` in [`backend/pkg/server/auth/auth_middleware.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/auth_middleware.go). This middleware:

1. Reads the session cookie and extracts claims (`uid`, `uhash`, `exp`, etc.)
2. Verifies the session has not expired
3. Validates the user hash matches the current database value (preventing cookie reuse after password changes)
4. Stores the identity in the Gin context (`c.Set("uid", ...)`) for downstream handlers

Sessions that fail any check return `authResultFail`, forcing re-authentication.

## OAuth2 Single Sign-On (Google and GitHub)

### Authorization Request Flow

Pentagi supports OAuth2 SSO through `GET /api/v1/auth/authorize`, handled by `AuthAuthorize` in [`backend/pkg/server/services/auth.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/services/auth.go). The endpoint:

1. Generates a cryptographically random **state** parameter (signed HMAC with JSON payload)
2. Stores a **nonce** in a SameSite-appropriate cookie
3. Redirects the client to the provider's authorization URL (`oauthClient.AuthCodeURL`)

### Callback Handling and User Provisioning

After provider authentication, the callback handlers (`authLoginCallback` and related functions) process the authorization code:

1. Exchange the code for an access token using the OAuth2 client
2. Resolve the user's email via `oauthClient.ResolveEmail`
3. If the email does not exist in the `users` table, create a new **OAuth** user record
4. Build a session cookie identical to the local login flow, setting `tid` to `models.UserTypeOAuth`

This ensures SSO users receive the same session-based privileges as local users.

## API Token Authentication with JWT

### Token Structure and Validation

Pentagi implements machine-to-machine authentication using **JWT API tokens** defined in [`backend/pkg/server/auth/api_token_jwt.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/api_token_jwt.go). The token structure uses the `APITokenClaims` struct:

```go
type APITokenClaims struct {
    TokenID   string    `json:"tid"`
    UID       uint64    `json:"uid"`
    RID       uint64    `json:"rid"`
    UHASH     string    `json:"uhash"`
    ExpiresAt time.Time `json:"exp"`
}

```

The `ValidateAPIToken` function parses the JWT, verifies the HMAC signature using the global `cfg.CookieSigningSalt`, and returns the claims for further processing.

### Permission Lookup and Caching

API tokens receive their privileges through `TokenCache` in [`backend/pkg/server/auth/api_token_cache.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/api_token_cache.go). The `GetStatus` method:

1. Loads the token row from the database
2. Fetches the associated role's privileges
3. **Adds** the built-in `pentagi.automation` privilege (required for all API tokens)
4. Caches the result for 5 minutes to reduce database load

This ensures API tokens have both role-based and automation-specific permissions.

## Request-Level Authorization and Middleware

### Authentication Middleware (AuthUserRequired vs AuthTokenRequired)

Pentagi uses three distinct middleware patterns in [`backend/pkg/server/auth/auth_middleware.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/auth_middleware.go):

- **`TryAuth`**: Attempts authentication but allows anonymous access (used for public endpoints)
- **`AuthUserRequired`**: Enforces valid session cookies; rejects API tokens
- **`AuthTokenRequired`**: Enforces valid API tokens (JWT); rejects session cookies

The `AuthTokenRequired` middleware specifically invokes `tryProtoTokenAuthentication`, which extracts the Bearer token from the `Authorization` header, validates it via `ValidateAPIToken`, and populates the Gin context with `uid`, `rid`, `prm`, and other identity fields.

### Privilege-Based Access Control

Route handlers enforce fine-grained permissions using `auth.PrivilegesRequired` from [`backend/pkg/server/auth/permissions.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/permissions.go). This middleware:

1. Reads `c.GetStringSlice("prm")` (the privilege list stored by authentication middleware)
2. Compares against the required permissions passed as arguments
3. Aborts with **HTTP 403** if any required privilege is missing

Example implementation:

```go
router.Group("/api/v1").
    Use(authMiddleware.AuthUserRequired).
    GET("/admin/users", auth.PrivilegesRequired("users.read"), userService.GetUsers)

```

Only sessions or API tokens containing the `users.read` privilege can access this endpoint.

## Performance Optimizations with Caching

Pentagi implements two specialized caches to minimize database queries during authentication:

- **UserCache** ([`backend/pkg/server/auth/users_cache.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/users_cache.go)): Stores `<userID> → (hash, status)` mappings for 5 minutes. This prevents repeated database lookups when validating session cookies on every request.

- **TokenCache** ([`backend/pkg/server/auth/api_token_cache.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/api_token_cache.go)): Stores `<tokenID> → (status, privileges)` mappings with the same 5-minute expiration. This accelerates API token validation by avoiding privilege lookups on everyauthenticated request.

Both caches invalidate entries immediately when users or tokens are updated (e.g., password changes or token revocation), ensuring security is not compromised by stale data.

## Summary

- Pentagi uses a **layered security model** supporting local sessions, OAuth2 SSO (Google/GitHub), and JWT API tokens.
- **Session authentication** relies on signed Gin cookies with bcrypt password validation and hash-based replay protection.
- **OAuth2 flow** generates signed state parameters, handles provider callbacks, and provisions new users automatically.
- **API tokens** use HMAC-signed JWTs with built-in `pentagi.automation` privileges and cached permission lookups.
- **Middleware enforces** authentication via `AuthUserRequired` (sessions) or `AuthTokenRequired` (JWTs), while `PrivilegesRequired` handles fine-grained authorization.
- **Caching layers** (`UserCache`, `TokenCache`) optimize performance by reducing database queries during request validation.

## Frequently Asked Questions

### What authentication methods does Pentagi support?

Pentagi supports three primary authentication methods: **local session-based login** using email and password with bcrypt hashing, **OAuth2 Single Sign-On** through Google and GitHub providers, and **API token authentication** using JWTs for machine-to-machine access. All methods ultimately populate the Gin context with user identity and privilege information.

### How does Pentagi validate API tokens?

API tokens are validated in [`backend/pkg/server/auth/api_token_jwt.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/api_token_jwt.go) through the `ValidateAPIToken` function. The system parses the JWT, verifies the HMAC signature using the global `CookieSigningSalt`, and extracts claims including `TokenID`, `UID`, `RID`, and `ExpiresAt`. The `TokenCache` then loads the corresponding privileges and adds the mandatory `pentagi.automation` permission.

### What is the difference between AuthUserRequired and AuthTokenRequired?

`AuthUserRequired` enforces **session cookie authentication**, rejecting requests that present API tokens and requiring valid session data from the Gin session store. `AuthTokenRequired` enforces **JWT bearer token authentication**, extracting tokens from the `Authorization` header and rejecting session-based requests. Both middleware populate the same context keys (`uid`, `prm`, etc.), allowing downstream handlers to work with either authentication type.

### How are user privileges checked in Pentagi?

Privilege checks occur through the `PrivilegesRequired` middleware in [`backend/pkg/server/auth/permissions.go`](https://github.com/vxcontrol/pentagi/blob/main/backend/pkg/server/auth/permissions.go). This middleware reads the `prm` (privileges) slice from the Gin context, which was populated by either session or token authentication middleware, and verifies that the user possesses all required permissions. If any privilege is missing, the middleware aborts the request with HTTP 403 before the route handler executes.