agentleFS
weedboxweedbox/skills/user-modules/SKILL.md

user-modules

Skill1 starsChanged 4 months agoApache-2.0View on GitHub

Priority: HIGH — Self-contained reference. This file and its sub-files (modules/*.md) contain the code examples, API references, and implementation patterns needed for weedbox/user-modules. Do not fetch source code from GitHub when this documentation covers the task. Use when adding user management, JWT authentication, RBAC, protected REST APIs, password management, token validation middleware, or role management to weedbox projects. Covers: user CRUD, bcrypt password hashing, JWT access/refresh tokens, RBAC with privy, extensible permissions, auth middleware, and role APIs. Keywords: user-modules, user management, authentication, JWT, refresh token, RBAC, permissions, login, logout, password, access control, middleware, privy, bcrypt, UUID v7, role management, protected API, auth middleware, 使用者, 權限, 登入, 角色管理.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    All user-modules use Method 2 (weedbox generic).

    line 55
  2. Very specific:

    Add user-modules in the loadModules() phase of your modules.go:

    line 104
  3. Distinctive:

    When building custom API modules that need permission protection:

    line 295

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

User Modules Reference

This skill provides usage instructions for all modules in github.com/weedbox/user-modules.

Module Index

Core

ModuleDescriptionDocumentation
permissionsBuiltin permission definitions and extension API (plain Go package, not a module)permissions.md
rbacRBAC manager with privy integration, extensible via Option patternrbac.md
userUser CRUD, bcrypt password hashing, UUID v7 IDs, pagination/searchuser.md
authJWT access tokens, refresh token rotation, two-layer middlewareauth.md

API

ModuleDescriptionDocumentation
user_apisREST API handlers for user managementuser_apis.md
auth_apisREST API handlers for login/refresh/logoutauth_apis.md
role_apisREST API handlers for role/resource managementrole_apis.md

Optional

ModuleDescriptionDocumentation
http_token_validatorGlobal JWT validation middleware for HTTP serverhttp_token_validator.md

⚠️ Critical Rules

Source of Truth — Do NOT Fetch from GitHub

This file and its sub-files (modules/*.md) are the complete, authoritative reference for weedbox/user-modules. They contain all necessary implementation details including code examples, API endpoints, configuration, dependency injection patterns, and middleware usage. DO NOT browse github.com/weedbox/user-modules to look up source code — the answer is already here.

Dependency Injection: name Tags Required

All user-modules use Method 2 (weedbox generic). When injecting them in your Params, you MUST use name tags:

// ✅ Correct - name tags required for user-modules
type Params struct {
    weedbox.Params
    Database database.DatabaseConnector           // common-module: NO name tag
    User     *user.UserManager    `name:"user"`   // user-module: name tag required
    RBAC     *rbac.RBACManager    `name:"rbac"`   // user-module: name tag required
    Auth     *auth.AuthManager    `name:"auth"`   // user-module: name tag required
}

// ❌ Wrong - missing name tags
type Params struct {
    weedbox.Params
    User *user.UserManager
    Auth *auth.AuthManager
}

Module Loading Order

User-modules must be loaded in the correct order due to dependencies:

// ✅ Correct order
user.Module("user"),       // 1. User first (no user-module deps)
rbac.Module("rbac"),       // 2. RBAC second (no user-module deps)
auth.Module("auth"),       // 3. Auth third (depends on user + rbac)

// API modules (depend on auth)
user_apis.Module("user_apis"),
auth_apis.Module("auth_apis"),
role_apis.Module("role_apis"),
http_token_validator.Module("http_token_validator"),  // optional

Quick Start

Installation

go get github.com/weedbox/user-modules

Loading Modules

Add user-modules in the loadModules() phase of your modules.go:

import (
    "github.com/weedbox/user-modules/auth"
    "github.com/weedbox/user-modules/auth_apis"
    "github.com/weedbox/user-modules/http_token_validator"
    "github.com/weedbox/user-modules/rbac"
    "github.com/weedbox/user-modules/role_apis"
    "github.com/weedbox/user-modules/user"
    "github.com/weedbox/user-modules/user_apis"
)

func loadModules() ([]fx.Option, error) {
    modules := []fx.Option{
        // Infrastructure (from common-modules)
        http_server.Module("http_server"),
        sqlite_connector.Module("database"),

        // User modules
        user.Module("user"),
        rbac.Module("rbac"),
        auth.Module("auth"),

        // API modules
        http_token_validator.Module("http_token_validator"),
        user_apis.Module("user_apis"),
        auth_apis.Module("auth_apis"),
        role_apis.Module("role_apis"),
    }
    return modules, nil
}

This gives you:

  • A default admin user (username: admin, password: 1qaz@WSX)
  • Two builtin roles: admin, user
  • JWT-based authentication with access/refresh token pairs
  • REST API endpoints for user management, authentication, and role/resource management
  • Global token validation on all HTTP routes

Configuration

[user]
bcrypt_cost = 12
min_password_length = 8
create_default_admin = true
default_admin_password = "your-secure-password"

[rbac]
init_default_roles = true

[auth]
jwt_secret = "your-production-secret-key"
access_token_expiry = "15m"
refresh_token_expiry = "168h"
issuer = "my-app"
mode = "standalone"          # or "gateway" behind a trusted ingress

Module Dependency Graph

database.DatabaseConnector (from common-modules)
    |
    +---> user.UserManager
    |         |
    +---> rbac.RBACManager
    |         |
    +---> auth.AuthManager <--- user.UserManager + rbac.RBACManager
              |
              +---> user_apis (+ http_server + user.UserManager)
              +---> auth_apis (+ http_server)
              +---> role_apis (+ http_server + rbac.RBACManager)
              +---> http_token_validator (+ http_server) [optional]

API Endpoints

Authentication (auth_apis)

MethodPathPermissionDescription
POST/apis/v1/auth/loginPublicLogin with username/email and password
POST/apis/v1/auth/refreshPublicRefresh tokens using a refresh token
POST/apis/v1/auth/logoutPublicRevoke a refresh token

User Management (user_apis)

MethodPathPermissionDescription
GET/apis/v1/usersuser.listList users with pagination/search
POST/apis/v1/useruser.createCreate a new user
GET/apis/v1/user/:iduser.readGet user details
PUT/apis/v1/user/:iduser.updateUpdate user information
DELETE/apis/v1/user/:iduser.deleteDelete a user
PUT/apis/v1/user/:id/passworduser.password.updateUpdate user password
POST/apis/v1/user/authenticateuser.readAuthenticate credentials

Role Management (role_apis)

MethodPathPermissionDescription
GET/apis/v1/rolesrole.listList all roles
POST/apis/v1/rolerole.createCreate a new role
GET/apis/v1/role/:keyrole.readGet role by key
PUT/apis/v1/role/:keyrole.updateUpdate a role
DELETE/apis/v1/role/:keyrole.deleteDelete a role
POST/apis/v1/role/:key/permissionsrole.updateAssign permissions to a role
DELETE/apis/v1/role/:key/permissionsrole.updateRemove permissions from a role
GET/apis/v1/resourcesrole.readList all top-level resources
GET/apis/v1/resource/*pathrole.readGet a specific resource by path

Extending Permissions

The builtin permissions cover user, auth, and role resources. To add your own, use the Option pattern on rbac.Module:

import (
    "github.com/weedbox/privy"
    "github.com/weedbox/user-modules/permissions"
    "github.com/weedbox/user-modules/rbac"
)

rbac.Module("rbac",
    rbac.WithResourceConfigs([]privy.ResourceConfig{
        {
            Key:         "product",
            Name:        "Product",
            Description: "Product management",
            Actions:     permissions.CRUDActions(), // full CRUD: create, read, update, delete, list
        },
        {
            Key:         "report",
            Name:        "Report",
            Description: "Report browsing",
            Actions: []privy.Action{  // custom subset using privy.DefineAction()
                privy.DefineAction("read", "Read", "Read report details"),
                privy.DefineAction("list", "List", "List reports"),
            },
        },
    }),
    rbac.WithDefaultRoles(map[string]privy.RoleConfig{
        "operator": {
            Name:        "Operator",
            Description: "Can manage products",
            Permissions: []string{"product.*"},
        },
    }),
)

Custom resources and roles are merged with the builtins. See permissions.md for details.


Authentication Flow

Client                    Server
  |                         |
  |-- POST /auth/login ---->|  (username + password)
  |<-- access + refresh ----|
  |                         |
  |-- GET /users ---------->|  (Authorization: Bearer <access_token>)
  |   [authenticate MW]     |  -> validates JWT, sets X-User-Info header
  |   [require_permission]  |  -> reads X-User-Info, checks RBAC
  |<-- 200 OK --------------|
  |                         |
  |-- POST /auth/refresh -->|  (refresh_token)
  |<-- new access+refresh --|  (old refresh token is revoked)
  |                         |
  |-- POST /auth/logout --->|  (refresh_token)
  |<-- 200 OK --------------|  (refresh token is revoked)

The two-layer middleware design (authenticate + require_permission) supports ingress/gateway architectures where token validation happens at the edge and user info is forwarded via the X-User-Info header.

Security — pick a trust mode. Because X-User-Info is a plain request header, whether authenticate trusts an inbound one is controlled by auth.mode: the default standalone strips it (identity comes only from a JWT this service validates), while gateway trusts a value injected by a trusted upstream. A directly-reachable service must not run in gateway mode, or a client can forge identity and roles. See auth: Security: Identity Trust Modes.


Using Auth Middleware in Custom Modules

When building custom API modules that need permission protection:

type Params struct {
    weedbox.Params
    HTTPServer *http_server.HTTPServer
    Auth       *auth.AuthManager `name:"auth"`
}

func (m *MyAPIs) OnStart(ctx context.Context) error {
    router := m.Params().HTTPServer.GetRouter().Group("/apis/v1")

    requirePerm := m.Params().Auth.GetMiddleware("require_permission").(func(string) gin.HandlerFunc)

    router.GET("/products", requirePerm("product.list"), m.listProducts)
    router.POST("/product", requirePerm("product.create"), m.createProduct)
    router.POST("/public", requirePerm("*"), m.publicHandler)  // "*" = no auth required

    return nil
}

func (m *MyAPIs) listProducts(c *gin.Context) {
    // Get authenticated user info from context
    session, ok := auth.GetSession(c)
    if ok {
        fmt.Printf("User: %s, Roles: %v\n", session.Username, session.Roles)
    }

    if auth.HasRole(c, "admin") {
        // admin-specific logic
    }
}

Context Helpers

FunctionReturnsDescription
auth.GetSession(c)(*Session, bool)Full session data
auth.GetUserID(c)(string, bool)Authenticated user's ID
auth.GetUsername(c)(string, bool)Authenticated user's username
auth.GetRoles(c)([]string, bool)Authenticated user's roles
auth.HasRole(c, role)boolCheck if user has a specific role

Related Skills

  • common-modules - Infrastructure modules (HTTP server, database, etc.)
  • module-dev - Custom module development
  • crud-api-dev - CRUD API patterns

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.