{
  "schemaVersion": "1.0",
  "item": {
    "slug": "user-authentication-system",
    "name": "User Authentication System",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/satoshistackalotto/user-authentication-system",
    "canonicalUrl": "https://clawhub.ai/satoshistackalotto/user-authentication-system",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/user-authentication-system",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=user-authentication-system",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "EVALS.json",
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "user-authentication-system",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-10T13:22:41.447Z",
      "expiresAt": "2026-05-17T13:22:41.447Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=user-authentication-system",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=user-authentication-system",
        "contentDisposition": "attachment; filename=\"user-authentication-system-0.1.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "user-authentication-system"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/user-authentication-system"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/user-authentication-system",
    "agentPageUrl": "https://openagent3.xyz/skills/user-authentication-system/agent",
    "manifestUrl": "https://openagent3.xyz/skills/user-authentication-system/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/user-authentication-system/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "User Authentication System",
        "body": "This skill provides a complete authentication and authorization system for Greek accounting firm operations through OpenClaw. It manages user identities, role-based permissions, per-client access controls, and session security for multi-user accounting environments."
      },
      {
        "title": "Setup",
        "body": "export OPENCLAW_DATA_DIR=\"/data\"\nwhich jq openssl || sudo apt install jq openssl\nmkdir -p $OPENCLAW_DATA_DIR/auth\nchmod 700 $OPENCLAW_DATA_DIR/auth\n\nNo external auth services. User credentials are stored as salted SHA-256 hashes locally. 2FA uses SHA-256 TOTP generated by openssl."
      },
      {
        "title": "Core Philosophy",
        "body": "Role-Based Access: Hierarchical permissions matching real accounting firm structures\nPer-Client Authorization: Granular control over which users access which client data\nSession Security: Secure session management with timeout and device tracking\nAudit Integration: Every authentication and authorization event logged\nOpenClaw Artifact Ready: File-based auth suitable for OpenClaw deployment"
      },
      {
        "title": "User Management",
        "body": "openclaw auth user-create --username \"maria.g\" --role assistant --full-name \"Maria Georgiou\" --email \"maria@firm.gr\"\nopenclaw auth user-update --username \"maria.g\" --role accountant --effective-date 2026-03-01\nopenclaw auth user-deactivate --username \"maria.g\" --reason \"resignation\" --revoke-sessions\nopenclaw auth user-list --active --role assistant --format table\nopenclaw auth password-reset --username \"maria.g\" --send-reset-link\nopenclaw auth password-policy --min-length 12 --require-special --max-age-days 90"
      },
      {
        "title": "Role & Permission Management",
        "body": "openclaw auth role-list --include-permissions\nopenclaw auth role-create --name \"tax_specialist\" --base-role accountant --add-permissions \"tax_filing,tax_optimization\"\nopenclaw auth assign-clients --username \"maria.g\" --clients EL123456789,EL987654321\nopenclaw auth assign-clients --username \"maria.g\" --all-clients\nopenclaw auth check-access --username \"maria.g\" --client EL123456789 --action \"view_financials\"\nopenclaw auth access-matrix --all-users --all-clients --format xlsx"
      },
      {
        "title": "Security & Audit",
        "body": "openclaw auth security-log --last-24h --include-failures\nopenclaw auth failed-logins --threshold 3 --lockout-duration 30m\nopenclaw auth audit-report --user \"maria.g\" --period last-30-days\nopenclaw auth audit-report --client EL123456789 --who-accessed --period last-week\nopenclaw auth 2fa-enable --username \"maria.g\" --method totp\nopenclaw auth sessions-list --active --format table\nopenclaw auth session-revoke --username \"maria.g\" --all-devices"
      },
      {
        "title": "File System Architecture",
        "body": "Auth_File_Structure:\n  user_data:\n    - /data/auth/users/{username}/profile.json\n    - /data/auth/users/{username}/credentials.json\n    - /data/auth/users/{username}/permissions.json\n    - /data/auth/users/{username}/sessions/\n    - /data/auth/users/{username}/2fa/\n\n  role_definitions:\n    - /data/auth/roles/senior_accountant.json\n    - /data/auth/roles/accountant.json\n    - /data/auth/roles/assistant.json\n    - /data/auth/roles/viewer.json\n    - /data/auth/roles/custom/\n\n  access_control:\n    - /data/auth/access/client_assignments.json\n    - /data/auth/access/policies.json\n    - /data/auth/access/ip_whitelist.json\n\n  security_logs:\n    - /data/auth/logs/logins/\n    - /data/auth/logs/access/\n    - /data/auth/logs/admin/\n    - /data/auth/logs/security/"
      },
      {
        "title": "Role Definitions",
        "body": "Roles:\n  senior_accountant:\n    description: \"Senior accountant - full system access\"\n    level: 4\n    inherits: \"accountant\"\n    permissions:\n      - all_client_access\n      - user_management\n      - role_assignment\n      - system_configuration\n      - data_export_all\n      - compliance_override\n      - audit_log_access\n      - gdpr_operations\n      - billing_management\n      - skill_configuration\n    client_access: \"all\"\n\n  accountant:\n    description: \"Accountant - broad access to assigned clients\"\n    level: 3\n    inherits: \"assistant\"\n    permissions:\n      - client_data_full_access\n      - tax_filing_submit\n      - tax_optimization\n      - compliance_management\n      - financial_reporting\n      - efka_submissions\n      - banking_reconciliation\n      - deadline_management\n      - client_communication\n    client_access: \"assigned_only\"\n    restrictions:\n      - cannot_manage_users\n      - cannot_change_system_config\n\n  assistant:\n    description: \"Accountant assistant - operational access\"\n    level: 2\n    inherits: \"viewer\"\n    permissions:\n      - document_upload\n      - document_processing\n      - data_entry\n      - email_processing\n      - dashboard_access\n      - basic_reporting\n      - client_data_edit_basic\n      - alert_acknowledgement\n      - ocr_processing\n    client_access: \"assigned_only\"\n    restrictions:\n      - cannot_submit_tax_filings\n      - cannot_export_sensitive_data\n      - cannot_modify_financial_records\n\n  viewer:\n    description: \"Read-only access to assigned client data\"\n    level: 1\n    permissions:\n      - dashboard_view\n      - client_data_view\n      - report_view\n      - deadline_view\n      - document_view\n    client_access: \"assigned_only\"\n    restrictions:\n      - read_only\n      - no_data_modification\n      - no_data_export"
      },
      {
        "title": "Permission Matrix",
        "body": "Permission_Matrix:\n  view_dashboard: \"viewer\"\n  configure_dashboard: \"accountant\"\n  view_client_profile: \"viewer\"\n  edit_client_profile: \"assistant\"\n  create_client: \"accountant\"\n  delete_client: \"senior_accountant\"\n  export_client_data: \"accountant\"\n  gdpr_operations: \"senior_accountant\"\n  view_documents: \"viewer\"\n  upload_documents: \"assistant\"\n  process_documents: \"assistant\"\n  delete_documents: \"accountant\"\n  view_financials: \"viewer\"\n  enter_financial_data: \"assistant\"\n  modify_financial_records: \"accountant\"\n  submit_tax_filings: \"accountant\"\n  view_compliance_status: \"viewer\"\n  manage_compliance: \"accountant\"\n  override_compliance: \"senior_accountant\"\n  view_employee_data: \"viewer\"\n  manage_employees: \"accountant\"\n  submit_efka: \"accountant\"\n  view_transactions: \"viewer\"\n  reconcile_transactions: \"assistant\"\n  configure_banking: \"accountant\"\n  manage_users: \"senior_accountant\"\n  manage_roles: \"senior_accountant\"\n  view_audit_logs: \"senior_accountant\"\n  system_configuration: \"senior_accountant\""
      },
      {
        "title": "Core Authentication",
        "body": "class AuthenticationEngine:\n    \"\"\"Handles user authentication, sessions, and credential management.\"\"\"\n\n    def __init__(self):\n        self.session_timeout = 30 * 60  # 30 minutes\n        self.idle_timeout = 15 * 60     # 15 minutes\n        self.max_failed_attempts = 5\n        self.lockout_duration = 30 * 60  # 30 minutes\n\n    def authenticate(self, username, password, device_info=None):\n        \"\"\"Authenticate user and create session.\"\"\"\n        if self.is_account_locked(username):\n            self.log_auth_event(username, 'login_blocked', 'account_locked')\n            return {'success': False, 'error': 'Account is locked. Contact administrator.'}\n\n        user = self.load_user(username)\n        if not user:\n            self.log_auth_event(username, 'login_failed', 'user_not_found')\n            return {'success': False, 'error': 'Invalid credentials'}\n\n        if not self.verify_password(password, user['password_hash']):\n            self.record_failed_attempt(username)\n            self.log_auth_event(username, 'login_failed', 'wrong_password')\n            return {'success': False, 'error': 'Invalid credentials'}\n\n        if user['status'] != 'active':\n            self.log_auth_event(username, 'login_failed', f'account_{user[\"status\"]}')\n            return {'success': False, 'error': 'Account is not active'}\n\n        if user.get('2fa_enabled', False):\n            return {'success': False, 'requires_2fa': True,\n                    'session_pending': self.create_pending_session(username)}\n\n        session = self.create_session(username, device_info)\n        self.clear_failed_attempts(username)\n        self.log_auth_event(username, 'login_success', device_info=device_info)\n        return {'success': True, 'session': session, 'user': self.get_user_summary(username)}\n\n    def create_session(self, username, device_info=None):\n        \"\"\"Create a new authenticated session.\n        \n        Security: The raw session token is returned to the user exactly once.\n        Only the salted SHA-256 hash is stored on disk. Validation compares\n        the hash of the incoming token against the stored hash.\n        \"\"\"\n        raw_token = generate_secure_token(64)\n        token_hash = hash_session_token(raw_token)  # SHA-256 salted hash\n        session = {\n            'session_id': token_hash,\n            'username': username,\n            'created_at': current_timestamp(),\n            'expires_at': current_timestamp() + self.session_timeout,\n            'last_activity': current_timestamp(),\n            'device_info': device_info,\n            'ip_address': get_request_ip(),\n            'role': self.get_user_role(username),\n            'client_access': self.get_user_client_access(username)\n        }\n        session_path = f\"/data/auth/users/{username}/sessions/{token_hash}.json\"\n        write_json(session_path, session)\n        # Return raw token to user — this is the only time it exists in cleartext\n        session['bearer_token'] = raw_token\n        return session\n\n    def validate_session(self, session_id):\n        \"\"\"Validate an existing session.\"\"\"\n        session = self.find_session(session_id)\n        if not session:\n            return {'valid': False, 'reason': 'session_not_found'}\n        if current_timestamp() > session['expires_at']:\n            self.destroy_session(session_id)\n            return {'valid': False, 'reason': 'session_expired'}\n        if current_timestamp() - session['last_activity'] > self.idle_timeout:\n            self.destroy_session(session_id)\n            return {'valid': False, 'reason': 'idle_timeout'}\n        session['last_activity'] = current_timestamp()\n        self.update_session(session)\n        return {'valid': True, 'session': session}\n\n    def hash_password(self, password):\n        \"\"\"Hash password using bcrypt with salt.\"\"\"\n        return bcrypt_hash(password, rounds=12)\n\n    def validate_password_strength(self, password):\n        \"\"\"Check password meets policy requirements.\"\"\"\n        errors = []\n        if len(password) < 12:\n            errors.append(\"Password must be at least 12 characters\")\n        if not any(c.isupper() for c in password):\n            errors.append(\"Must contain uppercase letter\")\n        if not any(c.islower() for c in password):\n            errors.append(\"Must contain lowercase letter\")\n        if not any(c.isdigit() for c in password):\n            errors.append(\"Must contain digit\")\n        if not any(c in '!@#$%^&*()_+-=' for c in password):\n            errors.append(\"Must contain special character\")\n        return {'valid': len(errors) == 0, 'errors': errors}"
      },
      {
        "title": "Authorization Engine",
        "body": "class AuthorizationEngine:\n    \"\"\"Handles permission checks and access control decisions.\"\"\"\n\n    def __init__(self):\n        self.roles = self.load_roles()\n        self.access_matrix = self.load_access_matrix()\n\n    def check_permission(self, session, action, client_vat=None):\n        \"\"\"Check if user has permission to perform an action.\"\"\"\n        username = session['username']\n        user_role = session['role']\n\n        required_role = self.access_matrix.get(action)\n        if not required_role:\n            self.log_authorization(username, action, client_vat, 'denied', 'unknown_action')\n            return {'allowed': False, 'reason': f'Unknown action: {action}'}\n\n        user_level = self.roles[user_role]['level']\n        required_level = self.roles[required_role]['level']\n\n        if user_level < required_level:\n            self.log_authorization(username, action, client_vat, 'denied', 'insufficient_role')\n            return {'allowed': False,\n                    'reason': f'Requires {required_role} role (you have {user_role})'}\n\n        # Check client-specific access\n        if client_vat:\n            client_access = session.get('client_access', [])\n            if 'all' not in client_access and client_vat not in client_access:\n                self.log_authorization(username, action, client_vat, 'denied', 'no_client_access')\n                return {'allowed': False,\n                        'reason': f'Not authorized for client {AFM}'}\n\n        self.log_authorization(username, action, client_vat, 'allowed')\n        return {'allowed': True}\n\n    def resolve_permissions(self, role_name):\n        \"\"\"Resolve all permissions including inherited ones.\"\"\"\n        role = self.roles.get(role_name, {})\n        permissions = set(role.get('permissions', []))\n        parent = role.get('inherits')\n        if parent:\n            permissions.update(self.resolve_permissions(parent))\n        return permissions\n\n    def get_accessible_clients(self, username):\n        \"\"\"Get list of clients this user can access.\"\"\"\n        assignments = read_json(\"/data/auth/access/client_assignments.json\")\n        user_entry = assignments.get(username, {})\n        if user_entry.get('all_clients', False):\n            return {'type': 'all', 'clients': 'all'}\n        return {'type': 'specific', 'clients': user_entry.get('clients', [])}"
      },
      {
        "title": "User Management",
        "body": "class UserManager:\n    \"\"\"Manages user lifecycle operations.\"\"\"\n\n    def __init__(self):\n        self.auth_engine = AuthenticationEngine()\n        self.authz_engine = AuthorizationEngine()\n\n    def create_user(self, admin_session, user_data):\n        \"\"\"Create a new user account.\"\"\"\n        # Verify admin has permission\n        perm_check = self.authz_engine.check_permission(admin_session, 'manage_users')\n        if not perm_check['allowed']:\n            return {'success': False, 'error': perm_check['reason']}\n\n        username = user_data['username']\n\n        # Check for duplicate\n        if self.user_exists(username):\n            return {'success': False, 'error': f'Username {username} already exists'}\n\n        # Validate role\n        if user_data['role'] not in self.authz_engine.roles:\n            return {'success': False, 'error': f'Invalid role: {user_data[\"role\"]}'}\n\n        # Create user profile\n        profile = {\n            'username': username,\n            'full_name': user_data['full_name'],\n            'email': user_data.get('email'),\n            'role': user_data['role'],\n            'status': 'active',\n            'created_at': current_timestamp(),\n            'created_by': admin_session['username'],\n            'password_change_required': True,\n            '2fa_enabled': False\n        }\n\n        # Generate temporary password\n        temp_password = generate_secure_password()\n        credentials = {\n            'password_hash': self.auth_engine.hash_password(temp_password),\n            'password_set_at': current_timestamp(),\n            'password_change_required': True\n        }\n\n        # Create user directory and files\n        user_dir = f\"/data/auth/users/{username}\"\n        create_directory(user_dir)\n        create_directory(f\"{user_dir}/sessions\")\n        create_directory(f\"{user_dir}/2fa\")\n        write_json(f\"{user_dir}/profile.json\", profile)\n        write_json(f\"{user_dir}/credentials.json\", credentials)\n        write_json(f\"{user_dir}/permissions.json\", {'role': user_data['role'], 'custom': []})\n\n        # Audit log\n        self.log_admin_action(admin_session['username'], 'user_created', {\n            'new_user': username, 'role': user_data['role']\n        })\n\n        return {\n            'success': True,\n            'username': username,\n            'temporary_password': temp_password,\n            'message': f'User {username} created with role {user_data[\"role\"]}. '\n                       f'Password change required on first login.'\n        }\n\n    def assign_clients(self, admin_session, username, client_vats):\n        \"\"\"Assign client access to a user.\"\"\"\n        perm_check = self.authz_engine.check_permission(admin_session, 'manage_users')\n        if not perm_check['allowed']:\n            return {'success': False, 'error': perm_check['reason']}\n\n        assignments_path = \"/data/auth/access/client_assignments.json\"\n        assignments = read_json(assignments_path) if file_exists(assignments_path) else {}\n\n        if client_vats == 'all':\n            assignments[username] = {'all_clients': True, 'clients': []}\n        else:\n            current = assignments.get(username, {'all_clients': False, 'clients': []})\n            current['clients'] = list(set(current.get('clients', []) + client_vats))\n            assignments[username] = current\n\n        write_json(assignments_path, assignments)\n\n        self.log_admin_action(admin_session['username'], 'clients_assigned', {\n            'user': username, 'clients': client_vats\n        })\n\n        return {'success': True, 'username': username, 'client_access': assignments[username]}"
      },
      {
        "title": "File System Permissions (Production Hardening)",
        "body": "The /data/auth/ directory contains sensitive credential and session data. In production, OS-level file permissions must be hardened:\n\n# Restrict the entire auth directory\nchmod 700 /data/auth/\nchown -R openclaw:openclaw /data/auth/\n\n# Credential files must be read-only to the service user\nchmod 600 /data/auth/users/*/credentials.json\n\n# Session files\nchmod 600 /data/auth/users/*/sessions/*.json\n\n# Role definitions (read by all skills for auth checks, writable only by admin)\nchmod 644 /data/auth/roles/*.json\n\n# Audit logs (append-only in production if OS supports it)\nchmod 600 /data/auth/logs/**/*.json\n\nNote: The OpenClaw agent and all skills share the same file system context. Without OS-level permission restrictions, any skill could read credential hashes. These permissions ensure that only the authentication skill's process can access sensitive auth data."
      },
      {
        "title": "Account Lockout",
        "body": "Lockout_Policy:\n  max_failed_attempts: 5\n  lockout_duration: \"30 minutes\"\n  lockout_escalation:\n    - \"5 failures: 30 minute lockout\"\n    - \"10 failures: 2 hour lockout\"\n    - \"15 failures: account disabled, admin notification\"\n  notification: \"email admin on 3+ consecutive failures\""
      },
      {
        "title": "Two-Factor Authentication",
        "body": "2FA_Configuration:\n  methods: [\"totp\"]\n  mandatory_for: [\"senior_accountant\"]\n  optional_for: [\"accountant\", \"assistant\"]\n  recovery_codes: 10\n  totp_settings:\n    algorithm: \"SHA256\"\n    digits: 6\n    period: 30"
      },
      {
        "title": "Password Policy",
        "body": "Password_Policy:\n  min_length: 12\n  require_uppercase: true\n  require_lowercase: true\n  require_digit: true\n  require_special: true\n  max_age_days: 90\n  history_count: 5\n  common_password_check: true"
      },
      {
        "title": "IP & Device Security",
        "body": "Security_Controls:\n  ip_whitelist:\n    enabled: true\n    allowed_ranges: [\"office_ip_range\"]\n    action_on_violation: \"block_and_alert\"\n\n  device_tracking:\n    track_devices: true\n    alert_new_device: true\n    max_concurrent_sessions: 3\n\n  session_controls:\n    absolute_timeout: \"8 hours\"\n    idle_timeout: \"15 minutes\"\n    single_session_per_device: true"
      },
      {
        "title": "Integration with Other Skills",
        "body": "Skill_Integration:\n  dashboard_greek_accounting:\n    provides: [\"user_session\", \"role_permissions\", \"accessible_clients\"]\n    enforces: \"dashboard view permissions per user role\"\n\n  client_data_management:\n    provides: [\"access_decisions\", \"user_identity\"]\n    enforces: \"per-client data access based on user assignments\"\n    integration: \"authorization check before every data operation\"\n\n  greek_compliance_aade:\n    enforces: \"only accountant+ can submit filings\"\n\n  efka_api_integration:\n    enforces: \"only accountant+ can submit EFKA data\"\n\n  all_skills:\n    provides: \"user context for audit trail entries\"\n    enforces: \"role-based action restrictions across all operations\""
      },
      {
        "title": "Audit Log Structure",
        "body": "Audit_Events:\n  authentication:\n    - login_success\n    - login_failed\n    - login_blocked\n    - logout\n    - session_expired\n    - session_revoked\n    - 2fa_success\n    - 2fa_failed\n    - password_changed\n    - password_reset\n\n  authorization:\n    - access_granted\n    - access_denied\n    - client_access_checked\n    - permission_checked\n\n  administration:\n    - user_created\n    - user_updated\n    - user_deactivated\n    - role_changed\n    - clients_assigned\n    - clients_revoked\n    - policy_changed\n\nAudit_Entry_Format:\n  timestamp: \"ISO 8601 with timezone\"\n  event_type: \"category.action\"\n  username: \"acting user\"\n  target: \"affected resource\"\n  client_vat: \"if client-specific\"\n  result: \"success/failure\"\n  details: \"additional context\"\n  ip_address: \"source IP\"\n  session_id: \"active session\""
      },
      {
        "title": "Success Metrics",
        "body": "A successful authentication system deployment should achieve:\n\n✅ Secure Authentication: bcrypt password hashing, optional 2FA, session management\n✅ Role Hierarchy: Four-level role system matching accounting firm structures\n✅ Per-Client Access: Granular client data access assignment per user\n✅ Session Security: Timeout, idle detection, concurrent session limits\n✅ Complete Audit Trail: Every auth/authz event logged with context\n✅ Account Protection: Lockout policy, password requirements, brute-force prevention\n✅ Cross-Skill Enforcement: Authorization integrated into all data operations\n✅ Admin Tools: User management, access matrix, security reporting\n✅ GDPR Compatible: Access controls support data protection requirements\n✅ Scalable: Handle 50+ users across 500+ clients\n\nRemember: The authentication system is the security foundation for the entire Greek accounting platform. Every data access must pass through authorization checks, and every action must leave an audit trail."
      }
    ],
    "body": "User Authentication System\n\nThis skill provides a complete authentication and authorization system for Greek accounting firm operations through OpenClaw. It manages user identities, role-based permissions, per-client access controls, and session security for multi-user accounting environments.\n\nSetup\nexport OPENCLAW_DATA_DIR=\"/data\"\nwhich jq openssl || sudo apt install jq openssl\nmkdir -p $OPENCLAW_DATA_DIR/auth\nchmod 700 $OPENCLAW_DATA_DIR/auth\n\n\nNo external auth services. User credentials are stored as salted SHA-256 hashes locally. 2FA uses SHA-256 TOTP generated by openssl.\n\nCore Philosophy\nRole-Based Access: Hierarchical permissions matching real accounting firm structures\nPer-Client Authorization: Granular control over which users access which client data\nSession Security: Secure session management with timeout and device tracking\nAudit Integration: Every authentication and authorization event logged\nOpenClaw Artifact Ready: File-based auth suitable for OpenClaw deployment\nOpenClaw Commands\nUser Management\nopenclaw auth user-create --username \"maria.g\" --role assistant --full-name \"Maria Georgiou\" --email \"maria@firm.gr\"\nopenclaw auth user-update --username \"maria.g\" --role accountant --effective-date 2026-03-01\nopenclaw auth user-deactivate --username \"maria.g\" --reason \"resignation\" --revoke-sessions\nopenclaw auth user-list --active --role assistant --format table\nopenclaw auth password-reset --username \"maria.g\" --send-reset-link\nopenclaw auth password-policy --min-length 12 --require-special --max-age-days 90\n\nRole & Permission Management\nopenclaw auth role-list --include-permissions\nopenclaw auth role-create --name \"tax_specialist\" --base-role accountant --add-permissions \"tax_filing,tax_optimization\"\nopenclaw auth assign-clients --username \"maria.g\" --clients EL123456789,EL987654321\nopenclaw auth assign-clients --username \"maria.g\" --all-clients\nopenclaw auth check-access --username \"maria.g\" --client EL123456789 --action \"view_financials\"\nopenclaw auth access-matrix --all-users --all-clients --format xlsx\n\nSecurity & Audit\nopenclaw auth security-log --last-24h --include-failures\nopenclaw auth failed-logins --threshold 3 --lockout-duration 30m\nopenclaw auth audit-report --user \"maria.g\" --period last-30-days\nopenclaw auth audit-report --client EL123456789 --who-accessed --period last-week\nopenclaw auth 2fa-enable --username \"maria.g\" --method totp\nopenclaw auth sessions-list --active --format table\nopenclaw auth session-revoke --username \"maria.g\" --all-devices\n\nFile System Architecture\nAuth_File_Structure:\n  user_data:\n    - /data/auth/users/{username}/profile.json\n    - /data/auth/users/{username}/credentials.json\n    - /data/auth/users/{username}/permissions.json\n    - /data/auth/users/{username}/sessions/\n    - /data/auth/users/{username}/2fa/\n\n  role_definitions:\n    - /data/auth/roles/senior_accountant.json\n    - /data/auth/roles/accountant.json\n    - /data/auth/roles/assistant.json\n    - /data/auth/roles/viewer.json\n    - /data/auth/roles/custom/\n\n  access_control:\n    - /data/auth/access/client_assignments.json\n    - /data/auth/access/policies.json\n    - /data/auth/access/ip_whitelist.json\n\n  security_logs:\n    - /data/auth/logs/logins/\n    - /data/auth/logs/access/\n    - /data/auth/logs/admin/\n    - /data/auth/logs/security/\n\nRole Hierarchy & Permissions\nRole Definitions\nRoles:\n  senior_accountant:\n    description: \"Senior accountant - full system access\"\n    level: 4\n    inherits: \"accountant\"\n    permissions:\n      - all_client_access\n      - user_management\n      - role_assignment\n      - system_configuration\n      - data_export_all\n      - compliance_override\n      - audit_log_access\n      - gdpr_operations\n      - billing_management\n      - skill_configuration\n    client_access: \"all\"\n\n  accountant:\n    description: \"Accountant - broad access to assigned clients\"\n    level: 3\n    inherits: \"assistant\"\n    permissions:\n      - client_data_full_access\n      - tax_filing_submit\n      - tax_optimization\n      - compliance_management\n      - financial_reporting\n      - efka_submissions\n      - banking_reconciliation\n      - deadline_management\n      - client_communication\n    client_access: \"assigned_only\"\n    restrictions:\n      - cannot_manage_users\n      - cannot_change_system_config\n\n  assistant:\n    description: \"Accountant assistant - operational access\"\n    level: 2\n    inherits: \"viewer\"\n    permissions:\n      - document_upload\n      - document_processing\n      - data_entry\n      - email_processing\n      - dashboard_access\n      - basic_reporting\n      - client_data_edit_basic\n      - alert_acknowledgement\n      - ocr_processing\n    client_access: \"assigned_only\"\n    restrictions:\n      - cannot_submit_tax_filings\n      - cannot_export_sensitive_data\n      - cannot_modify_financial_records\n\n  viewer:\n    description: \"Read-only access to assigned client data\"\n    level: 1\n    permissions:\n      - dashboard_view\n      - client_data_view\n      - report_view\n      - deadline_view\n      - document_view\n    client_access: \"assigned_only\"\n    restrictions:\n      - read_only\n      - no_data_modification\n      - no_data_export\n\nPermission Matrix\nPermission_Matrix:\n  view_dashboard: \"viewer\"\n  configure_dashboard: \"accountant\"\n  view_client_profile: \"viewer\"\n  edit_client_profile: \"assistant\"\n  create_client: \"accountant\"\n  delete_client: \"senior_accountant\"\n  export_client_data: \"accountant\"\n  gdpr_operations: \"senior_accountant\"\n  view_documents: \"viewer\"\n  upload_documents: \"assistant\"\n  process_documents: \"assistant\"\n  delete_documents: \"accountant\"\n  view_financials: \"viewer\"\n  enter_financial_data: \"assistant\"\n  modify_financial_records: \"accountant\"\n  submit_tax_filings: \"accountant\"\n  view_compliance_status: \"viewer\"\n  manage_compliance: \"accountant\"\n  override_compliance: \"senior_accountant\"\n  view_employee_data: \"viewer\"\n  manage_employees: \"accountant\"\n  submit_efka: \"accountant\"\n  view_transactions: \"viewer\"\n  reconcile_transactions: \"assistant\"\n  configure_banking: \"accountant\"\n  manage_users: \"senior_accountant\"\n  manage_roles: \"senior_accountant\"\n  view_audit_logs: \"senior_accountant\"\n  system_configuration: \"senior_accountant\"\n\nAuthentication Engine\nCore Authentication\nclass AuthenticationEngine:\n    \"\"\"Handles user authentication, sessions, and credential management.\"\"\"\n\n    def __init__(self):\n        self.session_timeout = 30 * 60  # 30 minutes\n        self.idle_timeout = 15 * 60     # 15 minutes\n        self.max_failed_attempts = 5\n        self.lockout_duration = 30 * 60  # 30 minutes\n\n    def authenticate(self, username, password, device_info=None):\n        \"\"\"Authenticate user and create session.\"\"\"\n        if self.is_account_locked(username):\n            self.log_auth_event(username, 'login_blocked', 'account_locked')\n            return {'success': False, 'error': 'Account is locked. Contact administrator.'}\n\n        user = self.load_user(username)\n        if not user:\n            self.log_auth_event(username, 'login_failed', 'user_not_found')\n            return {'success': False, 'error': 'Invalid credentials'}\n\n        if not self.verify_password(password, user['password_hash']):\n            self.record_failed_attempt(username)\n            self.log_auth_event(username, 'login_failed', 'wrong_password')\n            return {'success': False, 'error': 'Invalid credentials'}\n\n        if user['status'] != 'active':\n            self.log_auth_event(username, 'login_failed', f'account_{user[\"status\"]}')\n            return {'success': False, 'error': 'Account is not active'}\n\n        if user.get('2fa_enabled', False):\n            return {'success': False, 'requires_2fa': True,\n                    'session_pending': self.create_pending_session(username)}\n\n        session = self.create_session(username, device_info)\n        self.clear_failed_attempts(username)\n        self.log_auth_event(username, 'login_success', device_info=device_info)\n        return {'success': True, 'session': session, 'user': self.get_user_summary(username)}\n\n    def create_session(self, username, device_info=None):\n        \"\"\"Create a new authenticated session.\n        \n        Security: The raw session token is returned to the user exactly once.\n        Only the salted SHA-256 hash is stored on disk. Validation compares\n        the hash of the incoming token against the stored hash.\n        \"\"\"\n        raw_token = generate_secure_token(64)\n        token_hash = hash_session_token(raw_token)  # SHA-256 salted hash\n        session = {\n            'session_id': token_hash,\n            'username': username,\n            'created_at': current_timestamp(),\n            'expires_at': current_timestamp() + self.session_timeout,\n            'last_activity': current_timestamp(),\n            'device_info': device_info,\n            'ip_address': get_request_ip(),\n            'role': self.get_user_role(username),\n            'client_access': self.get_user_client_access(username)\n        }\n        session_path = f\"/data/auth/users/{username}/sessions/{token_hash}.json\"\n        write_json(session_path, session)\n        # Return raw token to user — this is the only time it exists in cleartext\n        session['bearer_token'] = raw_token\n        return session\n\n    def validate_session(self, session_id):\n        \"\"\"Validate an existing session.\"\"\"\n        session = self.find_session(session_id)\n        if not session:\n            return {'valid': False, 'reason': 'session_not_found'}\n        if current_timestamp() > session['expires_at']:\n            self.destroy_session(session_id)\n            return {'valid': False, 'reason': 'session_expired'}\n        if current_timestamp() - session['last_activity'] > self.idle_timeout:\n            self.destroy_session(session_id)\n            return {'valid': False, 'reason': 'idle_timeout'}\n        session['last_activity'] = current_timestamp()\n        self.update_session(session)\n        return {'valid': True, 'session': session}\n\n    def hash_password(self, password):\n        \"\"\"Hash password using bcrypt with salt.\"\"\"\n        return bcrypt_hash(password, rounds=12)\n\n    def validate_password_strength(self, password):\n        \"\"\"Check password meets policy requirements.\"\"\"\n        errors = []\n        if len(password) < 12:\n            errors.append(\"Password must be at least 12 characters\")\n        if not any(c.isupper() for c in password):\n            errors.append(\"Must contain uppercase letter\")\n        if not any(c.islower() for c in password):\n            errors.append(\"Must contain lowercase letter\")\n        if not any(c.isdigit() for c in password):\n            errors.append(\"Must contain digit\")\n        if not any(c in '!@#$%^&*()_+-=' for c in password):\n            errors.append(\"Must contain special character\")\n        return {'valid': len(errors) == 0, 'errors': errors}\n\nAuthorization Engine\nclass AuthorizationEngine:\n    \"\"\"Handles permission checks and access control decisions.\"\"\"\n\n    def __init__(self):\n        self.roles = self.load_roles()\n        self.access_matrix = self.load_access_matrix()\n\n    def check_permission(self, session, action, client_vat=None):\n        \"\"\"Check if user has permission to perform an action.\"\"\"\n        username = session['username']\n        user_role = session['role']\n\n        required_role = self.access_matrix.get(action)\n        if not required_role:\n            self.log_authorization(username, action, client_vat, 'denied', 'unknown_action')\n            return {'allowed': False, 'reason': f'Unknown action: {action}'}\n\n        user_level = self.roles[user_role]['level']\n        required_level = self.roles[required_role]['level']\n\n        if user_level < required_level:\n            self.log_authorization(username, action, client_vat, 'denied', 'insufficient_role')\n            return {'allowed': False,\n                    'reason': f'Requires {required_role} role (you have {user_role})'}\n\n        # Check client-specific access\n        if client_vat:\n            client_access = session.get('client_access', [])\n            if 'all' not in client_access and client_vat not in client_access:\n                self.log_authorization(username, action, client_vat, 'denied', 'no_client_access')\n                return {'allowed': False,\n                        'reason': f'Not authorized for client {AFM}'}\n\n        self.log_authorization(username, action, client_vat, 'allowed')\n        return {'allowed': True}\n\n    def resolve_permissions(self, role_name):\n        \"\"\"Resolve all permissions including inherited ones.\"\"\"\n        role = self.roles.get(role_name, {})\n        permissions = set(role.get('permissions', []))\n        parent = role.get('inherits')\n        if parent:\n            permissions.update(self.resolve_permissions(parent))\n        return permissions\n\n    def get_accessible_clients(self, username):\n        \"\"\"Get list of clients this user can access.\"\"\"\n        assignments = read_json(\"/data/auth/access/client_assignments.json\")\n        user_entry = assignments.get(username, {})\n        if user_entry.get('all_clients', False):\n            return {'type': 'all', 'clients': 'all'}\n        return {'type': 'specific', 'clients': user_entry.get('clients', [])}\n\nUser Management\nclass UserManager:\n    \"\"\"Manages user lifecycle operations.\"\"\"\n\n    def __init__(self):\n        self.auth_engine = AuthenticationEngine()\n        self.authz_engine = AuthorizationEngine()\n\n    def create_user(self, admin_session, user_data):\n        \"\"\"Create a new user account.\"\"\"\n        # Verify admin has permission\n        perm_check = self.authz_engine.check_permission(admin_session, 'manage_users')\n        if not perm_check['allowed']:\n            return {'success': False, 'error': perm_check['reason']}\n\n        username = user_data['username']\n\n        # Check for duplicate\n        if self.user_exists(username):\n            return {'success': False, 'error': f'Username {username} already exists'}\n\n        # Validate role\n        if user_data['role'] not in self.authz_engine.roles:\n            return {'success': False, 'error': f'Invalid role: {user_data[\"role\"]}'}\n\n        # Create user profile\n        profile = {\n            'username': username,\n            'full_name': user_data['full_name'],\n            'email': user_data.get('email'),\n            'role': user_data['role'],\n            'status': 'active',\n            'created_at': current_timestamp(),\n            'created_by': admin_session['username'],\n            'password_change_required': True,\n            '2fa_enabled': False\n        }\n\n        # Generate temporary password\n        temp_password = generate_secure_password()\n        credentials = {\n            'password_hash': self.auth_engine.hash_password(temp_password),\n            'password_set_at': current_timestamp(),\n            'password_change_required': True\n        }\n\n        # Create user directory and files\n        user_dir = f\"/data/auth/users/{username}\"\n        create_directory(user_dir)\n        create_directory(f\"{user_dir}/sessions\")\n        create_directory(f\"{user_dir}/2fa\")\n        write_json(f\"{user_dir}/profile.json\", profile)\n        write_json(f\"{user_dir}/credentials.json\", credentials)\n        write_json(f\"{user_dir}/permissions.json\", {'role': user_data['role'], 'custom': []})\n\n        # Audit log\n        self.log_admin_action(admin_session['username'], 'user_created', {\n            'new_user': username, 'role': user_data['role']\n        })\n\n        return {\n            'success': True,\n            'username': username,\n            'temporary_password': temp_password,\n            'message': f'User {username} created with role {user_data[\"role\"]}. '\n                       f'Password change required on first login.'\n        }\n\n    def assign_clients(self, admin_session, username, client_vats):\n        \"\"\"Assign client access to a user.\"\"\"\n        perm_check = self.authz_engine.check_permission(admin_session, 'manage_users')\n        if not perm_check['allowed']:\n            return {'success': False, 'error': perm_check['reason']}\n\n        assignments_path = \"/data/auth/access/client_assignments.json\"\n        assignments = read_json(assignments_path) if file_exists(assignments_path) else {}\n\n        if client_vats == 'all':\n            assignments[username] = {'all_clients': True, 'clients': []}\n        else:\n            current = assignments.get(username, {'all_clients': False, 'clients': []})\n            current['clients'] = list(set(current.get('clients', []) + client_vats))\n            assignments[username] = current\n\n        write_json(assignments_path, assignments)\n\n        self.log_admin_action(admin_session['username'], 'clients_assigned', {\n            'user': username, 'clients': client_vats\n        })\n\n        return {'success': True, 'username': username, 'client_access': assignments[username]}\n\nSecurity Features\nFile System Permissions (Production Hardening)\n\nThe /data/auth/ directory contains sensitive credential and session data. In production, OS-level file permissions must be hardened:\n\n# Restrict the entire auth directory\nchmod 700 /data/auth/\nchown -R openclaw:openclaw /data/auth/\n\n# Credential files must be read-only to the service user\nchmod 600 /data/auth/users/*/credentials.json\n\n# Session files\nchmod 600 /data/auth/users/*/sessions/*.json\n\n# Role definitions (read by all skills for auth checks, writable only by admin)\nchmod 644 /data/auth/roles/*.json\n\n# Audit logs (append-only in production if OS supports it)\nchmod 600 /data/auth/logs/**/*.json\n\n\nNote: The OpenClaw agent and all skills share the same file system context. Without OS-level permission restrictions, any skill could read credential hashes. These permissions ensure that only the authentication skill's process can access sensitive auth data.\n\nAccount Lockout\nLockout_Policy:\n  max_failed_attempts: 5\n  lockout_duration: \"30 minutes\"\n  lockout_escalation:\n    - \"5 failures: 30 minute lockout\"\n    - \"10 failures: 2 hour lockout\"\n    - \"15 failures: account disabled, admin notification\"\n  notification: \"email admin on 3+ consecutive failures\"\n\nTwo-Factor Authentication\n2FA_Configuration:\n  methods: [\"totp\"]\n  mandatory_for: [\"senior_accountant\"]\n  optional_for: [\"accountant\", \"assistant\"]\n  recovery_codes: 10\n  totp_settings:\n    algorithm: \"SHA256\"\n    digits: 6\n    period: 30\n\nPassword Policy\nPassword_Policy:\n  min_length: 12\n  require_uppercase: true\n  require_lowercase: true\n  require_digit: true\n  require_special: true\n  max_age_days: 90\n  history_count: 5\n  common_password_check: true\n\nIP & Device Security\nSecurity_Controls:\n  ip_whitelist:\n    enabled: true\n    allowed_ranges: [\"office_ip_range\"]\n    action_on_violation: \"block_and_alert\"\n\n  device_tracking:\n    track_devices: true\n    alert_new_device: true\n    max_concurrent_sessions: 3\n\n  session_controls:\n    absolute_timeout: \"8 hours\"\n    idle_timeout: \"15 minutes\"\n    single_session_per_device: true\n\nIntegration with Other Skills\nSkill_Integration:\n  dashboard_greek_accounting:\n    provides: [\"user_session\", \"role_permissions\", \"accessible_clients\"]\n    enforces: \"dashboard view permissions per user role\"\n\n  client_data_management:\n    provides: [\"access_decisions\", \"user_identity\"]\n    enforces: \"per-client data access based on user assignments\"\n    integration: \"authorization check before every data operation\"\n\n  greek_compliance_aade:\n    enforces: \"only accountant+ can submit filings\"\n\n  efka_api_integration:\n    enforces: \"only accountant+ can submit EFKA data\"\n\n  all_skills:\n    provides: \"user context for audit trail entries\"\n    enforces: \"role-based action restrictions across all operations\"\n\nAudit & Compliance Reporting\nAudit Log Structure\nAudit_Events:\n  authentication:\n    - login_success\n    - login_failed\n    - login_blocked\n    - logout\n    - session_expired\n    - session_revoked\n    - 2fa_success\n    - 2fa_failed\n    - password_changed\n    - password_reset\n\n  authorization:\n    - access_granted\n    - access_denied\n    - client_access_checked\n    - permission_checked\n\n  administration:\n    - user_created\n    - user_updated\n    - user_deactivated\n    - role_changed\n    - clients_assigned\n    - clients_revoked\n    - policy_changed\n\nAudit_Entry_Format:\n  timestamp: \"ISO 8601 with timezone\"\n  event_type: \"category.action\"\n  username: \"acting user\"\n  target: \"affected resource\"\n  client_vat: \"if client-specific\"\n  result: \"success/failure\"\n  details: \"additional context\"\n  ip_address: \"source IP\"\n  session_id: \"active session\"\n\nSuccess Metrics\n\nA successful authentication system deployment should achieve:\n\n✅ Secure Authentication: bcrypt password hashing, optional 2FA, session management\n✅ Role Hierarchy: Four-level role system matching accounting firm structures\n✅ Per-Client Access: Granular client data access assignment per user\n✅ Session Security: Timeout, idle detection, concurrent session limits\n✅ Complete Audit Trail: Every auth/authz event logged with context\n✅ Account Protection: Lockout policy, password requirements, brute-force prevention\n✅ Cross-Skill Enforcement: Authorization integrated into all data operations\n✅ Admin Tools: User management, access matrix, security reporting\n✅ GDPR Compatible: Access controls support data protection requirements\n✅ Scalable: Handle 50+ users across 500+ clients\n\nRemember: The authentication system is the security foundation for the entire Greek accounting platform. Every data access must pass through authorization checks, and every action must leave an audit trail."
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/satoshistackalotto/user-authentication-system",
    "publisherUrl": "https://clawhub.ai/satoshistackalotto/user-authentication-system",
    "owner": "satoshistackalotto",
    "version": "0.1.1",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/user-authentication-system",
    "downloadUrl": "https://openagent3.xyz/downloads/user-authentication-system",
    "agentUrl": "https://openagent3.xyz/skills/user-authentication-system/agent",
    "manifestUrl": "https://openagent3.xyz/skills/user-authentication-system/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/user-authentication-system/agent.md"
  }
}