Overview
User tokens are JWT (JSON Web Tokens) obtained through Auth0 OAuth 2.0 authentication. They are used for user-facing applications where individual users need to authenticate and access resources based on their permissions.
How It Works
User authentication follows the OAuth 2.0 authorization code flow:
Initiate Login
Your application redirects users to the Auth0 login endpoint: GET /api/v1/auth/login?redirect_uri=http://localhost:3000/dashboard
User Authenticates
Auth0 presents a login page where users authenticate with their credentials or social login providers.
Authorization Code
After successful authentication, Auth0 redirects back with an authorization code: GET /api/v1/auth/callback?code=AUTH_CODE&state=STATE_TOKEN
Token Exchange
The server exchanges the code for access and ID tokens containing user information.
Use Token
Your application receives a JWT token to authenticate API requests.
Configuration
Basic Setup
User token authentication is the default when creating a client:
import (
" context "
" os "
" github.com/garnet-org/api/client "
)
func main () {
token := os . Getenv ( "GARNET_USER_TOKEN" )
client := client . New ( "https://api.garnet.ai" , token )
// Make authenticated requests
var user UserInfo
err := client . Get ( context . Background (), & user , "/api/v1/me" )
if err != nil {
panic ( err )
}
}
When a token is provided to client.New(), it automatically sets TokenType to TokenTypeUser.
Explicit User Token Configuration
You can explicitly configure a client to use user tokens:
// WithUserToken configures the client to use a user token for authentication.
func ( c * Client ) WithUserToken ( token string ) * Client {
client := c . Clone ()
client . AuthToken = token
client . TokenType = TokenTypeUser
return client
}
// Switch an existing client to user token
userClient := client . WithUserToken ( "eyJhbGciOiJIUzI1NiIs..." )
User tokens are sent in the Authorization header with Bearer authentication:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
The SDK automatically handles the “Bearer ” prefix:
switch c . TokenType {
case TokenTypeUser :
// Check if it's already a bearer token
if strings . HasPrefix ( c . AuthToken , "Bearer " ) {
req . Header . Set ( "Authorization" , c . AuthToken )
} else {
req . Header . Set ( "Authorization" , "Bearer " + c . AuthToken )
}
}
Don’t manually add the “Bearer ” prefix. The SDK handles this automatically.
Permissions and RBAC
User tokens include role-based access control (RBAC) permissions. The API enforces granular permissions:
Permission Description createCreate new resources readView existing resources updateModify resources deleteRemove resources listList multiple resources
Example: Creating Project Tokens
Users can only create project tokens with permissions they themselves possess:
import " github.com/garnet-org/api/types "
// User with 'create' and 'read' permissions on tokens
createReq := types . CreateToken {
Name : "CI/CD Token" ,
Permissions : [] types . Permission {
types . PermissionTokenRead ,
types . PermissionTokenList ,
},
}
var tokenResp types . TokenCreated
err := client . Post ( ctx , & tokenResp , "/api/v1/tokens" , createReq )
Attempting to create a token with more permissions than you have results in a 403 Forbidden error.
Supported Endpoints
User tokens can access most API endpoints:
User Info : GET /api/v1/me
Agents : GET /api/v1/agents, POST /api/v1/agents, GET /api/v1/agents/{id}
Issues : GET /api/v1/issues, POST /api/v1/issues, PATCH /api/v1/issues/{id}
Events : GET /api/v1/events
Tokens : POST /api/v1/tokens, GET /api/v1/tokens, PATCH /api/v1/tokens/{id}
Network Policies : All network policy endpoints
Project Settings : All project settings endpoints
Token Lifecycle
Token Expiration
JWT tokens have an expiration time (exp claim). When a token expires, API requests return 401 Unauthorized:
err := client . Get ( ctx , & result , "/api/v1/agents" )
if err != nil && strings . Contains ( err . Error (), "401" ) {
// Token expired or invalid
// Redirect user to login
}
Logout
To log out a user, redirect them to the logout endpoint:
GET /api/v1/auth/logout?returnTo=http://localhost:3000
This clears the Auth0 session and redirects to the specified URL.
Security Best Practices
Critical Security Guidelines
Never Hardcode Tokens
// ❌ BAD: Hardcoded token
client := client . New ( "https://api.garnet.ai" , "eyJhbGciOiJIUzI1NiIs..." )
// ✅ GOOD: Environment variable
token := os . Getenv ( "GARNET_USER_TOKEN" )
client := client . New ( "https://api.garnet.ai" , token )
Validate Token Claims
Verify the token’s exp, iss, and aud claims before trusting it.
Use HTTPS Only
Always use HTTPS endpoints to prevent token interception: // ✅ GOOD: HTTPS
client := client . New ( "https://api.garnet.ai" , token )
// ❌ BAD: HTTP (insecure)
client := client . New ( "http://api.garnet.ai" , token )
Implement Token Refresh
Handle token expiration gracefully by implementing refresh logic or redirecting to login.
Secure Storage
Store tokens securely on the client side (e.g., httpOnly cookies, secure storage).
Error Handling
Common Authentication Errors
err := client . Get ( ctx , & result , "/api/v1/agents" )
if err != nil {
if strings . Contains ( err . Error (), "401" ) {
// Token is invalid, expired, or missing
return fmt . Errorf ( "authentication failed: %w " , err )
}
if strings . Contains ( err . Error (), "403" ) {
// Token is valid but lacks required permissions
return fmt . Errorf ( "permission denied: %w " , err )
}
}
Authorization Errors
The API returns resource-specific authorization errors:
UnauthorizedAgent: No access to agent resources
UnauthorizedIssue: No access to issue resources
UnauthorizedEvents: No access to event resources
UnauthorizedTokenAccess: No access to token resources
UnauthorizedNetworkPolicy: No access to network policy resources
Complete Example
package main
import (
" context "
" fmt "
" log "
" os "
" github.com/garnet-org/api/client "
" github.com/garnet-org/api/types "
)
func main () {
// Get token from environment
token := os . Getenv ( "GARNET_USER_TOKEN" )
if token == "" {
log . Fatal ( "GARNET_USER_TOKEN not set" )
}
// Create authenticated client
c := client . New ( "https://api.garnet.ai" , token )
// Get current user info
var user types . CurrentUserInfo
if err := c . Get ( context . Background (), & user , "/api/v1/me" ); err != nil {
log . Fatalf ( "Failed to get user info: %v " , err )
}
fmt . Printf ( "Authenticated as: %s \n " , user . Email )
fmt . Printf ( "Organization: %s \n " , user . OrganizationName )
fmt . Printf ( "Project: %s \n " , user . ProjectName )
}
Next Steps
Agent Tokens Learn about agent authentication
Project Tokens Set up programmatic access