What Authentication Methods Does Multica Support? JWT, PAT, OAuth, and Daemon Tokens Explained

Multica supports four distinct authentication mechanisms: JWT tokens for user sessions, Personal Access Tokens (PAT) for API access, Google OAuth for third-party sign-in, and Daemon Tokens for machine-to-machine authentication.

The multica-ai/multica repository implements a comprehensive authentication layer in its Go backend that covers interactive users, programmatic clients, and background daemon processes. Understanding what authentication methods Multica supports is essential for securely integrating with its REST API, whether you are building a web frontend, automating CI/CD pipelines, or deploying persistent agent daemons.

JSON Web Tokens (JWT)

Multica uses JWT (JSON Web Token) as its default session mechanism for authenticated users. These tokens are signed with HMAC-SHA256 and contain claims for the user ID, email, name, expiration (exp), and issued-at timestamp (iat).

JWT Generation

After successful email-code verification or Google OAuth login, the backend issues a JWT through the issueJWT function in server/internal/handler/auth.go:

func (h *Handler) issueJWT(user db.User) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "sub":   uuidToString(user.ID),   // user ID
        "email": user.Email,
        "name":  user.Name,
        "exp":   time.Now().Add(30 * 24 * time.Hour).Unix(),
        "iat":   time.Now().Unix(),
    })
    return token.SignedString(auth.JWTSecret())
}

The signing secret originates from the JWT_SECRET environment variable (with a development fallback).

JWT Validation

Incoming requests are validated by the Auth middleware in server/internal/middleware/auth.go. The middleware extracts the Authorization: Bearer <token> header, parses the JWT using the shared secret, and injects X-User-ID and X-User-Email headers into the request context:

token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) {
    if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
        return nil, jwt.ErrSignatureInvalid
    }
    return auth.JWTSecret(), nil
})

Personal Access Tokens (PAT)

For programmatic API access, Multica implements Personal Access Tokens (PAT). These are long-lived credentials that allow scripts and integrations to authenticate without user sessions.

PAT Structure and Generation

PATs are random 40-character hexadecimal strings prefixed with mul_. The GeneratePATToken function in server/internal/auth/jwt.go creates these tokens using cryptographic randomness:

func GeneratePATToken() (string, error) {
    b := make([]byte, 20) // 20 bytes → 40 hex chars
    if _, err := rand.Read(b); err != nil {
        return "", fmt.Errorf("generate PAT token: %w", err)
    }
    return "mul_" + hex.EncodeToString(b), nil
}

Secure Storage with SHA-256 Hashing

Security is enforced by never storing the raw token. Instead, the HashToken function computes a SHA-256 hash for database storage in the personal_access_tokens table:

func HashToken(token string) string {
    h := sha256.Sum256([]byte(token))
    return hex.EncodeToString(h[:])
}

PAT Validation in Middleware

When a request includes a mul_ prefixed token, the middleware in server/internal/middleware/auth.go hashes the presented token and queries the database for a matching hash:

if strings.HasPrefix(tokenString, "mul_") {
    hash := auth.HashToken(tokenString)
    pat, err := queries.GetPersonalAccessTokenByHash(r.Context(), hash)
    // …
}

Google OAuth Integration

Multica supports Google OAuth as a third-party authentication provider, enabling users to sign in with their Google accounts.

OAuth Flow Implementation

The GoogleLogin handler in server/internal/handler/auth.go manages the server-side exchange:

// Exchange the one‑time code for an access token.
tokenResp, err := http.PostForm("https://oauth2.googleapis.com/token", url.Values{
    "code":          {req.Code},
    "client_id":     {clientID},
    "client_secret": {clientSecret},
    "redirect_uri":  {redirectURI},
    "grant_type":    {"authorization_code"},
})

After exchanging the authorization code for an access token, the handler fetches the user's Google profile, creates or updates the local user record, and issues a standard JWT for session management.

Daemon Tokens

For machine-to-machine authentication between background agents and the API, Multica uses Daemon Tokens prefixed with mdt_.

Daemon Token Generation

Generated similarly to PATs via GenerateDaemonToken in server/internal/auth/jwt.go, these tokens use a distinct prefix to trigger separate validation logic:

func GenerateDaemonToken() (string, error) {
    b := make([]byte, 20)
    if _, err := rand.Read(b); err != nil {
        return "", fmt.Errorf("generate daemon token: %w", err)
    }
    return "mdt_" + hex.EncodeToString(b), nil
}

Workspace-Scoped Validation

The DaemonAuth middleware in server/internal/middleware/daemon_auth.go validates these tokens. It checks not only the token's validity against the daemon_tokens table but also enforces that the daemon can only access its assigned workspace:

if strings.HasPrefix(tokenString, "mdt_") {
    // look up token, verify workspace, then set X-Workspace-ID, X-User-ID …
}

Practical Code Examples

Authenticating with a JWT

curl -H "Authorization: Bearer <jwt-token>" \
     https://api.multica.ai/v1/issues

Using a Personal Access Token

curl -H "Authorization: Bearer mul_abcdef1234..." \
     https://api.multica.ai/v1/projects

Daemon Token Usage

curl -H "Authorization: Bearer mdt_1234abcd..." \
     -H "X-Workspace-ID: workspace-abc123" \
     https://api.multica.ai/v1/daemon/poll

Summary

  • JWT tokens provide temporary user sessions after email or OAuth login, validated by HMAC-SHA256 signatures in server/internal/middleware/auth.go.
  • Personal Access Tokens offer long-lived API credentials using mul_ prefixed hashes stored in the personal_access_tokens table.
  • Google OAuth enables third-party sign-in via the GoogleLogin handler, which exchanges codes for profiles and issues standard JWTs.
  • Daemon Tokens facilitate secure machine-to-machine authentication with workspace scoping via the DaemonAuth middleware.

Frequently Asked Questions

Can I use Multica without Google OAuth?

Yes. Multica supports email-based authentication with verification codes, which issues standard JWT tokens upon successful validation. OAuth is optional and implemented alongside the native email-code flow.

How are tokens revoked in Multica?

PATs and Daemon Tokens are revoked by deleting their SHA-256 hash entries from the respective database tables (personal_access_tokens or daemon_tokens). JWTs expire automatically based on their exp claim and cannot be individually revoked before expiration.

What is the difference between a PAT and a Daemon Token?

While both use similar cryptographic generation in server/internal/auth/jwt.go, PATs (mul_ prefix) are validated by the standard Auth middleware for user-level API access, whereas Daemon Tokens (mdt_ prefix) are processed by the DaemonAuth middleware which additionally enforces workspace isolation for background processes.

Is the JWT secret configurable?

Yes. The JWT_SECRET environment variable configures the HMAC-SHA256 signing key. If not provided, the system uses a development default, which should not be used in production environments.

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 →