The Forge Platform provides a centralized authentication and authorization service that handles:
- OAuth 2.0 authentication via Slack
- JWT token generation with role-based claims
- RBAC (Role-Based Access Control) for fine-grained permissions
- Multi-application support for all Forge Utah services
-
Auth Server (
cmd/auth-server/main.go)- Handles OAuth flow with Slack
- Issues JWT tokens with RBAC claims
- Provides authorization endpoints
- Manages user roles and permissions
-
TUI Client (
cmd/test-tui/main.go)- Terminal interface for testing authentication
- Demonstrates integration patterns
-
RBAC System
- Role and permission management
- Casbin-based policy enforcement
- Persistent storage of access control data
sequenceDiagram
User->>App: Access protected resource
App->>Auth Portal: Redirect to /login?app_id=myapp&callback=...
Auth Portal->>User: Show Forge Utah login page
User->>Auth Portal: Click "Login with Slack"
Auth Portal->>Slack: OAuth redirect
User->>Slack: Authorize
Slack->>Auth Portal: Callback with code
Auth Portal->>Auth Portal: Generate JWT with roles
Auth Portal->>App: POST tokens to callback URL
App->>User: Authenticated session
# Application opens browser to auth portal
https://auth.forge.utah/login?app_id=forge-cli&callback=http://localhost:8081/auth
# Auth server attempts to:
1. POST tokens to callback URL (if provided)
2. Auto-detect TUI on localhost ports 8081-8083
3. Display code for manual entry{
"user_id": "user_abc123",
"email": "user@forge.utah",
"name": "John Doe",
"slack_id": "U0123456789",
"workspace_id": "TC92KEFJT",
"roles": ["verified", "meetup_organizer"],
"permissions": [
"content:read",
"content:write",
"meetups:create",
"meetups:manage"
],
"type": "access",
"iat": 1703001234,
"exp": 1703087634
}| Role | Description | Default Permissions |
|---|---|---|
viewer |
Default for new users | View public content, meetups, projects |
verified |
Verified community members | Create content, RSVP to events, view profiles |
moderator |
Community moderators | Moderate content, ban users |
meetup_organizer |
Event organizers | Create/manage meetups, view analytics |
admin |
Organization administrators | Manage users, projects, settings |
super_admin |
Full system access | All permissions (admin:all) |
Permissions follow the format: resource:action
Resources:
content- Posts, comments, discussionsmeetups- Events and gatheringsusers- User accounts and profilesprojects- Forge Utah projectssettings- System configurationadmin- Administrative functions
Actions:
read- View resourcewrite- Create/edit resourcedelete- Remove resourcemoderate- Moderate contentmanage- Full managementverify- Verify usersban- Ban usersall- All actions
| Endpoint | Method | Description |
|---|---|---|
/ or /login |
GET | Login portal page |
/auth/start |
GET | Get OAuth URL (API) |
/callback |
GET | OAuth callback from Slack |
/auth/exchange |
POST | Exchange code for tokens |
| Endpoint | Method | Description | Required Permission |
|---|---|---|---|
/auth/check |
POST | Check user permission | None |
/auth/roles |
GET | Get user's roles | None |
/auth/permissions |
GET | Get user's permissions | None |
| Endpoint | Method | Description | Required Permission |
|---|---|---|---|
/admin/roles |
GET | List all roles | users:read |
/admin/permissions |
GET | List all permissions | users:read |
/admin/users/{id}/roles |
GET | Get user's roles | users:read |
/admin/users/{id}/roles |
POST | Assign role to user | users:write |
/admin/users/{id}/roles/{role} |
DELETE | Remove role from user | users:write |
// Web application
const loginUrl = new URL('https://auth.forge.utah/login');
loginUrl.searchParams.append('app_id', 'my-app');
loginUrl.searchParams.append('app_name', 'My Application');
loginUrl.searchParams.append('callback', 'https://myapp.com/auth/callback');
loginUrl.searchParams.append('redirect_uri', 'https://myapp.com/dashboard');
window.location.href = loginUrl.toString();// Receive tokens at your callback URL
type AuthCallback struct {
Code string `json:"code"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
User User `json:"user"`
ExpiresAt time.Time `json:"expires_at"`
}
func handleAuthCallback(w http.ResponseWriter, r *http.Request) {
var callback AuthCallback
json.NewDecoder(r.Body).Decode(&callback)
// Store tokens and create session
session.Set("access_token", callback.AccessToken)
session.Set("user", callback.User)
}// Check permission via API
func checkPermission(token, resource, action string) (bool, error) {
body := map[string]string{
"token": token,
"resource": resource,
"action": action,
}
resp, err := http.Post("https://auth.forge.utah/auth/check", "application/json", body)
// Handle response
}
// Or decode JWT locally for quick checks
claims := jwt.Parse(token)
if slices.Contains(claims["permissions"], "meetups:create") {
// User can create meetups
}# Slack OAuth
SLACK_CLIENT_ID=your_slack_client_id
SLACK_CLIENT_SECRET=your_slack_client_secret
SLACK_REDIRECT_URI=https://auth.forge.utah/callback
SLACK_TEAM_ID=TC92KEFJT # Forge Utah workspace
# JWT Configuration
JWT_SECRET=your-secret-key-change-in-production
JWT_EXPIRY_HOURS=24
# Server Configuration
PORT=3000
SERVER_URL=https://auth.forge.utah
# Casbin RBAC
CASBIN_MODEL_PATH=./config/auth_model.conf
CASBIN_POLICY_PATH=./config/auth_policy.csv- Create a Slack app at https://api.slack.com/apps
- Add OAuth scopes:
users:readusers:read.emailteam:read
- Set redirect URL to:
https://auth.forge.utah/callback - Install app to Forge Utah workspace
-
JWT Security
- Tokens expire after 24 hours (configurable)
- Refresh tokens valid for 30 days
- Secret key must be strong and rotated regularly
-
CORS Configuration
- Currently allows all origins (
*) for development - Should be restricted to known applications in production
- Currently allows all origins (
-
Permission Checks
- Always verify permissions server-side
- JWT claims are for optimization, not security
- Use
/auth/checkendpoint for critical operations
-
Data Protection
- RBAC data stored in
./data/rbac/ - Ensure proper file permissions
- Regular backups recommended
- RBAC data stored in
See deployment.md for production deployment instructions.
# Run auth server
go run cmd/auth-server/main.go
# Test with TUI client
go run cmd/test-tui/main.go
# Test permission check
curl -X POST https://auth.forge.utah/auth/check \
-H "Content-Type: application/json" \
-d '{
"token": "your-jwt-token",
"resource": "meetups",
"action": "create"
}'- Ensure the Slack app has proper user scopes
- Check that OAuth response includes
authed_userfield
- Check that
./data/rbac/directory is writable - Verify Casbin model file exists at configured path
- Ensure JWT_SECRET matches between services
- Check token expiration time
- Verify token type is "access" not "refresh"