Skip to content
Back to skills

Appfolio Install Auth

ASecurity

'Configure AppFolio Stack API authentication with OAuth 2.0.

  • 2,719 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 21, 2026
ai-agentstypescriptpythonbashnodeapi

Works with

  • claude code
  • cli
  • api

Security analysis

A100/100

Scanned September 21, 2026

npx -y skills add jeremylongshore/claude-code-plugins-plus --skill appfolio-install-auth --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Appfolio Install Auth?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Appfolio Install Auth
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jeremylongshore-appfolio-install-auth-5e7dc444/badge)](https://www.skillsdirectory.com/skills/jeremylongshore-appfolio-install-auth-5e7dc444)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: appfolio-install-auth
description: 'Configure AppFolio Stack API authentication with OAuth 2.0.

  Use when setting up property management API access, registering as an

  AppFolio Stack partner, or configuring client credentials for API calls.

  Trigger: "install appfolio", "setup appfolio", "appfolio auth", "appfolio API key".

  '
allowed-tools: Read, Write, Edit, Bash(npm:*), Bash(curl:*), Grep
version: 1.5.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
tags:
- saas
- property-management
- appfolio
- real-estate
compatibility: Designed for Claude Code
---
# AppFolio Install & Auth

## Overview

Configure AppFolio Stack API authentication. AppFolio uses HTTP Basic Auth with a client ID and client secret, provided through their Stack partner program. No public npm SDK exists — use direct REST API calls.

## Prerequisites

- AppFolio Stack partner account ([appfolio.com/stack](https://www.appfolio.com/stack/become-a-partner))
- Client ID and Client Secret from AppFolio
- Node.js 18+ or Python 3.10+

## Instructions

### Step 1: Obtain API Credentials

```bash
# AppFolio Stack API credentials come from the partner program
# 1. Apply at appfolio.com/stack/become-a-partner
# 2. Complete integration review
# 3. Receive the provider-issued base URL and credential delivery instructions.
# Store the values in the approved secret manager. Commit only this non-secret
# template if local development requires one:
cat > .env.example << 'ENVFILE'
APPFOLIO_CLIENT_ID=
APPFOLIO_CLIENT_SECRET=
APPFOLIO_BASE_URL=
ENVFILE

# .env remains ignored; populate it only through an approved local secret flow.
```

### Step 2: Create API Client

```typescript
// src/appfolio-client.ts
import axios, { AxiosInstance } from 'axios';

class AppFolioClient {
  private api: AxiosInstance;

  constructor() {
    this.api = axios.create({
      baseURL: process.env.APPFOLIO_BASE_URL,
      auth: {
        username: process.env.APPFOLIO_CLIENT_ID!,
        password: process.env.APPFOLIO_CLIENT_SECRET!,
      },
      headers: { 'Content-Type': 'application/json' },
      timeout: 30000,
    });
  }

  async verifyConnection(): Promise<boolean> {
    try {
      const response = await this.api.get('/properties');
      console.log(`Connected! Found ${response.data.length} properties`);
      return true;
    } catch (error: any) {
      console.error(`Connection failed: ${error.response?.status} ${error.message}`);
      return false;
    }
  }

  get http(): AxiosInstance { return this.api; }
}

export { AppFolioClient };
```

### Step 3: Verify Connection

```bash
# Quick, redacted diagnostic without putting Basic Auth in argv.
NETRC_FILE="$(mktemp)"
trap 'rm -f "$NETRC_FILE"' EXIT
chmod 600 "$NETRC_FILE"
APPFOLIO_HOST="${APPFOLIO_BASE_URL#https://}"
APPFOLIO_HOST="${APPFOLIO_HOST%%/*}"
printf 'machine %s login %s password %s\n' "$APPFOLIO_HOST" \
  "$APPFOLIO_CLIENT_ID" "$APPFOLIO_CLIENT_SECRET" > "$NETRC_FILE"
curl -s -o /dev/null -w '%{http_code}\n' --netrc-file "$NETRC_FILE" \
  "${APPFOLIO_BASE_URL}/properties"
```

## API Endpoints

| Resource | Endpoint | Methods |
|----------|----------|---------|
| Properties | `/api/v1/properties` | GET |
| Units | `/api/v1/units` | GET |
| Tenants | `/api/v1/tenants` | GET |
| Leases | `/api/v1/leases` | GET, POST |
| Bills | `/api/v1/bills` | GET, POST |
| Vendors | `/api/v1/vendors` | GET |
| Owners | `/api/v1/owners` | GET |
| Reports | `/api/v1/reports` | GET |

## Output

- Provider-issued credentials injected through the approved secret boundary
- TypeScript REST client with Basic Auth
- Redacted connectivity result for the approved safe-read endpoint

## Examples

For a first authentication rehearsal, inject a sandbox credential and the
provider-issued base URL through the local secret mechanism, then make one
read-only request to an approved synthetic property page. Record only the
status code and client configuration verdict; do not print a property payload,
client ID, secret, or full host/path in shared logs. If the contract, base URL,
secret binding, or status result is unverified, stop before any write workflow
and have the credential owner correct the configuration.

## Error Handling

| Error | Cause | Solution |
|-------|-------|----------|
| `401 Unauthorized` | Invalid credentials | Verify client_id/secret from AppFolio |
| `403 Forbidden` | Not a Stack partner | Complete partner application |
| `404 Not Found` | Wrong base URL | Use `your-company.appfolio.com` format |
| Timeout | Network issue | Check firewall allows HTTPS to appfolio.com |

## Resources

- [AppFolio Stack APIs](https://www.appfolio.com/stack/partners/api)
- [AppFolio Partner Program](https://www.appfolio.com/stack/become-a-partner)
- [AppFolio Engineering Blog](https://engineering.appfolio.com)

## Next Steps

Proceed to `appfolio-hello-world` for your first property query.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.