Agent Skills

extension-user-approval

Approval-based user management.

Install

npx skills add https://github.com/caffeinelabs/skills --skill extension-user-approval
SKILL.md

User Approval

User approval extension for Caffeine AI.

Overview

This skill adds approval-based user management. Users request access; admins approve or reject. Approved users gain access to protected features.

Prerequisite: You must follow extension-authorization first, as this integration depends on it.

Backend

Module API

The prefabricated module mo:caffeineai-user-approval/approval provides low-level approval state management. Do not modify it.

import AccessControl "mo:caffeineai-authorization/access-control";

module {
    public type ApprovalStatus = {
        #approved;
        #rejected;
        #pending;
    };

    public type UserApprovalState = { /* internal state */ };

    public func initState(accessControlState: AccessControl.AccessControlState) : UserApprovalState;

    public func isApproved(state : UserApprovalState, caller : Principal) : Bool;
    public func requestApproval(state : UserApprovalState, caller : Principal);
    public func setApproval(state : UserApprovalState, user : Principal, approval : ApprovalStatus);

    public type UserApprovalInfo = {
        principal : Principal;
        status : ApprovalStatus;
    };

    public func listApprovals(state : UserApprovalState) : [UserApprovalInfo];
}

Setup in main.mo

include MixinUserApproval(accessControlState, approvalState) MUST be placed in main.mo, not in a custom mixin file. Declare approvalState at actor top level and pass it into the mixin. The mixin provides these public endpoints automatically:

  • isCallerApproved()
  • requestApproval()
  • setApproval(user, status)
  • listApprovals()

Keep approvalState in scope for custom approval guards in app-specific endpoints.

Do NOT redeclare any of the mixin-provided functions.

import AccessControl "mo:caffeineai-authorization/access-control";
import MixinAuthorization "mo:caffeineai-authorization/MixinAuthorization";
import MixinUserApproval "mo:caffeineai-user-approval/MixinUserApproval";
import UserApproval "mo:caffeineai-user-approval/approval";
import Runtime "mo:core/Runtime";

actor {
    let accessControlState : AccessControl.AccessControlState;
    include MixinAuthorization(accessControlState, null);
    let approvalState : UserApproval.UserApprovalState;
    include MixinUserApproval(accessControlState, approvalState);

    // Example custom endpoint with an approval guard:
    // public shared ({ caller }) func protectedFeature() : async () {
    //     if (not (UserApproval.isApproved(approvalState, caller) or AccessControl.hasPermission(accessControlState, caller, #admin))) {
    //         Runtime.trap("Unauthorized: Only approved users can perform this action");
    //     };
    // };
};

The migration chain head — UserApproval.initState depends on the access-control state, so compute it in order inside the migration body:

import AccessControl "mo:caffeineai-authorization/access-control";
import UserApproval "mo:caffeineai-user-approval/approval";

module {
    type NewActor = {
        accessControlState : AccessControl.AccessControlState;
        approvalState : UserApproval.UserApprovalState;
    };

    public func migration(_old : {}) : NewActor {
        let accessControlState = AccessControl.initState();
        {
            accessControlState;
            approvalState = UserApproval.initState(accessControlState);
        };
    };
};

On initState, existing admins are automatically approved. All other users are pending.

IMPORTANT: Apply the right authorization and/or approval check to each custom public function.

Frontend

Approval-based user management:

User Approval Flow

  • Check approval status (isCallerApproved)
  • If not approved, show option to request approval (requestApproval)
  • Block access to main features for non-approved users
  • Admins have access to all features of the application
  • Display approval status clearly in the UI

Admin Dashboard

For admin users, provide a dashboard to:

  • List all users with their approval status (listApprovals)
  • Approve or reject users (setApproval)
  • View and assign user roles (using getCallerUserRole and assignCallerUserRole)

Backend Integration

The backend already implements the following functionality. The full interface can be found in

// Check if current user is approved, admins are always approved isCallerApproved(): Promise;

// Submit approval request requestApproval(): Promise;

// Get all users and their approval status (admin only) listApprovals(): Promise<Array>;

// Approve or reject a user (admin only) setApproval(user: Principal, status: ApprovalStatus): Promise;

// Assign a role to a user (admin only) assignCallerUserRole(user: Principal, role: UserRole): Promise;

// Get current role for a specific user getCallerUserRole(): Promise;

Related skills

entra-app-registrationmicrosoft606KGuides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.azure-messagingmicrosoft595KTroubleshoot and resolve issues with Azure Messaging SDKs for Event Hubs and Service Bus. Covers connection failures, authentication errors, message processing issues, and SDK configuration problems. WHEN: event hub SDK error, service bus SDK issue, messaging connection failure, AMQP error, event processor host issue, message lock lost, message lock expired, lock renewal, lock renewal batch, send timeout, receiver disconnected, SDK troubleshooting, azure messaging SDK, event hub consumer, servicentra-agent-idmicrosoft328KProvision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmi_path, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmi_path token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registsupabasesupabase298KUse when doing ANY task involving Supabase. Triggers: Supabase products (Database, Auth, Edge Functions, Realtime, Storage, Vectors, Cron, Queues); client libraries and SSR integrations (supabase-js, @supabase/ssr) in Next.js, React, SvelteKit, Astro, Remix; auth issues (login, logout, sessions, JWT, cookies, getSession, getUser, getClaims, RLS); Supabase CLI or MCP server; schema changes, migrations, declarative schemas, security audits, Postgres extensions (pg_graphql, pg_cron, pg_vector); deb

Search skills and MCP servers

Fuzzy search across 23,137 skills and servers