Skip to main content

Intuit QuickBooks OAuth 2.0 - Complete Guide

Last Updated: October 11, 2025
Version: 1.0.0
Status: βœ… Production Ready


Table of Contents​

  1. Overview
  2. Quick Start (20 minutes)
  3. Detailed Setup
  4. Environment Variables
  5. OAuth Scopes Configuration
  6. Database Setup
  7. Implementation Details
  8. Admin Dashboard Guide
  9. Usage in Code
  10. Security Features
  11. Troubleshooting
  12. API Reference
  13. Production Deployment

Overview​

This guide covers the complete Intuit QuickBooks OAuth 2.0 integration for secure payment processing in your Gully Sports application.

What This Integration Provides​

βœ… Payment Processing

  • Accept credit/debit card payments
  • Process ACH payments
  • Handle refunds and voids
  • Real-time authorization

βœ… Invoice Management

  • Auto-generate invoices
  • Send invoices to customers
  • Track payment status
  • Apply payments automatically

βœ… Customer Sync

  • Create customers in QuickBooks
  • Sync customer data
  • View payment history
  • Track spending patterns

βœ… Financial Reporting

  • Real-time sales data
  • Revenue tracking
  • Tax reporting
  • Financial analytics

βœ… Automatic Token Management

  • Tokens refresh automatically 5 minutes before expiration
  • AES-256-CBC encryption for stored tokens
  • Zero downtime payment processing
  • Secure storage in CockroachDB

Key Features​

  • πŸ”’ Enterprise-grade security with AES-256-CBC encryption
  • πŸ”„ Automatic token refresh prevents expiration issues
  • πŸ’³ Full payment processing capability
  • πŸ“„ Invoice generation and management
  • 🎨 Beautiful admin UI for easy management
  • πŸ“š Comprehensive documentation and examples

Quick Start​

Total Time: ~20 minutes

1. Create Intuit App (15 minutes)​

  1. Go to Intuit Developer Portal
  2. Sign in and navigate to "My Apps"
  3. Click "Create App"
  4. Select "QuickBooks Online and Payments"
  5. Fill in app details:
    • App Name: Your application name
    • Description: Brief description
  6. Go to "Keys & OAuth" section
  7. Note your Client ID and Client Secret
  8. Add Redirect URI: http://localhost:3000/api/admin/intuit/callback
  9. Select Scopes:
    • βœ… com.intuit.quickbooks.accounting
    • βœ… com.intuit.quickbooks.payment

2. Configure Environment Variables (2 minutes)​

Add to your .env.local file:

# Intuit OAuth Configuration
INTUIT_CLIENT_ID="your_client_id_from_intuit"
INTUIT_CLIENT_SECRET="your_client_secret_from_intuit"
INTUIT_REDIRECT_URI="http://localhost:3000/api/admin/intuit/callback"
INTUIT_ENCRYPTION_KEY="$(node -e 'console.log(require("crypto").randomBytes(32).toString("hex"))')"

# Optional: OAuth Scopes (defaults to accounting + payment)
INTUIT_OAUTH_SCOPE="com.intuit.quickbooks.accounting com.intuit.quickbooks.payment"

3. Run Database Migration (1 minute)​

npx prisma migrate deploy
npx prisma generate

4. Connect QuickBooks (2 minutes)​

  1. Start your dev server: npm run dev
  2. Log in as admin
  3. Go to Admin Dashboard at http://localhost:3000/admin
  4. Find "Intuit QuickBooks Integration" section
  5. Click "Connect to QuickBooks"
  6. Authorize on Intuit's page
  7. Done! βœ…

Detailed Setup​

Step 1: Intuit Developer Account Setup​

Create Your App​

  1. Visit Intuit Developer Portal
  2. Sign in with your Intuit account (create one if needed)
  3. Click "My Apps" in the top navigation
  4. Click "Create an app" button
  5. Select "QuickBooks Online and Payments" as the platform
  6. Fill in the application details:
    • App Display Name: "Gully Sports" (or your business name)
    • App Description: "Sports facility booking and e-commerce platform"
    • Industry: Sports & Recreation
    • Contact Email: Your business email

Configure OAuth Settings​

  1. Once created, go to your app dashboard
  2. Navigate to "Keys & OAuth" section
  3. Copy your Client ID and Client Secret (keep these secure!)
  4. In the "Redirect URIs" section, add:
    • Development: http://localhost:3000/api/admin/intuit/callback
    • Production: https://yourdomain.com/api/admin/intuit/callback
  5. In the "Scopes" section, select:
    • βœ… com.intuit.quickbooks.accounting - For invoicing and accounting
    • βœ… com.intuit.quickbooks.payment - For payment processing

Sandbox vs Production​

Intuit provides two environments:

Sandbox (Development)

  • Use for testing
  • No real money processed
  • Create test companies
  • Toggle between sandbox/production in app settings

Production

  • Live transactions
  • Real customer data
  • Requires app approval (for some features)
  • Use production credentials

Environment Variables​

Required Variables​

# ============================================
# Intuit OAuth Configuration
# ============================================

# Your Intuit app Client ID (from Developer Portal)
INTUIT_CLIENT_ID="ABCxyz123example"

# Your Intuit app Client Secret (from Developer Portal)
INTUIT_CLIENT_SECRET="xYz789ExampleSecret"

# OAuth callback URL (must match Intuit app settings exactly)
INTUIT_REDIRECT_URI="http://localhost:3000/api/admin/intuit/callback"

# Encryption key for token storage (generate a random 32+ character string)
INTUIT_ENCRYPTION_KEY="your_secure_random_32_character_key_here"

Optional Variables​

# OAuth Scopes (defaults to both if not specified)
INTUIT_OAUTH_SCOPE="com.intuit.quickbooks.accounting com.intuit.quickbooks.payment"

Generating the Encryption Key​

The encryption key is critical for secure token storage. Generate one using:

Using Node.js:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Using OpenSSL:

openssl rand -hex 32

Example Output:

a7f8e9d2c4b6a1f3e5d7c9b8a6f4e2d1c8b7a5f3e1d9c7b5a3f1e9d7c5b3a1f

⚠️ Important:

  • Never commit this key to version control
  • Use different keys for development and production
  • Store production keys in secure environment variables (Vercel, AWS, etc.)

Production Configuration​

For production, update:

INTUIT_REDIRECT_URI="https://yourdomain.com/api/admin/intuit/callback"
INTUIT_ENCRYPTION_KEY="different_key_for_production"

And add this URI to your Intuit app settings in the Developer Portal.


OAuth Scopes Configuration​

Overview​

The INTUIT_OAUTH_SCOPE environment variable controls what permissions your app requests from QuickBooks.

Default Configuration​

By default, both scopes are requested for full functionality:

INTUIT_OAUTH_SCOPE="com.intuit.quickbooks.accounting com.intuit.quickbooks.payment"

If not set, this is the automatic default.

Available Scopes​

1. QuickBooks Accounting (com.intuit.quickbooks.accounting)​

What it provides:

βœ… Invoice Management

  • Create, read, update invoices
  • Send invoices to customers
  • Track invoice status and payments
  • Apply payments to invoices

βœ… Customer Management

  • Create and manage customer records
  • Update customer information
  • View customer details and history
  • Customer payment tracking

βœ… Sales & Receipts

  • Record direct sales
  • Create sales receipts
  • Track cash transactions

βœ… Products & Services

  • Manage items catalog
  • Product pricing
  • Inventory tracking (read-only)

βœ… Financial Data

  • Access chart of accounts
  • View financial reports
  • Company information
  • Tax information

βœ… Estimates & Credit Memos

  • Create estimates and quotes
  • Issue refunds and credits
  • Apply credits to invoices

Best for: Invoice generation, customer sync, financial reporting


2. QuickBooks Payments (com.intuit.quickbooks.payment)​

What it provides:

βœ… Credit Card Processing

  • Process credit/debit card payments
  • Real-time authorization
  • Payment capture

βœ… Payment Tokenization

  • Securely tokenize card details
  • Store payment methods safely
  • PCI compliance support

βœ… Charge Management

  • Create payment charges
  • Capture authorized payments
  • Process refunds
  • Void transactions

βœ… ACH Payments (if enabled)

  • Bank account payments
  • ACH debit processing

βœ… Transaction Details

  • Payment history
  • Transaction status
  • Settlement information

Best for: Direct payment processing, credit card charges, refunds

Configuration Examples​

INTUIT_OAUTH_SCOPE="com.intuit.quickbooks.accounting com.intuit.quickbooks.payment"

Use when:

  • Processing credit cards during checkout
  • Generating invoices automatically
  • Need complete QuickBooks integration
  • Full payment and accounting features

Accounting Only​

INTUIT_OAUTH_SCOPE="com.intuit.quickbooks.accounting"

Use when:

  • Only generating invoices (customers pay later)
  • Using separate payment processor (Stripe, etc.)
  • Don't process credit cards directly
  • Just need customer and invoice sync

Payment Only (Rare)​

INTUIT_OAUTH_SCOPE="com.intuit.quickbooks.payment"

Use when:

  • Only need payment gateway functionality
  • Have separate invoicing system
  • Don't use QuickBooks for accounting

Scope Comparison Matrix​

FeatureAccounting ScopePayment ScopeBoth Scopes
Create Invoicesβœ… Yes❌ Noβœ… Yes
Process Credit Cards❌ Noβœ… Yesβœ… Yes
Customer Managementβœ… Yes❌ Noβœ… Yes
Payment Gateway❌ Noβœ… Yesβœ… Yes
Financial Reportsβœ… Yes❌ Noβœ… Yes
Refund Processing⚠️ Record onlyβœ… Processβœ… Both
Sales Receiptsβœ… Yes❌ Noβœ… Yes
ACH Payments❌ Noβœ… Yesβœ… Yes

Changing Scopes​

Important: Changing scopes requires reconnection!

  1. Update INTUIT_OAUTH_SCOPE in .env.local
  2. Restart your application
  3. Go to Admin Dashboard
  4. Click "Reconnect" button
  5. Authorize with new permissions

Database Setup​

Schema Overview​

The integration adds an IntuitOAuth table to securely store OAuth tokens:

model IntuitOAuth {
id String @id @default(cuid())
realmId String @unique // QuickBooks Company ID
accessToken String // Encrypted access token
refreshToken String // Encrypted refresh token
expiresAt DateTime // When the access token expires
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@index([realmId])
}

Running the Migration​

The migration file is already created at:

prisma/migrations/20251011002507_add_intuit_oauth/migration.sql

Apply the Migration​

# For development
npx prisma migrate deploy

# Regenerate Prisma Client
npx prisma generate

Verify Migration​

# Check migration status
npx prisma migrate status

# Should show: Database schema is up to date!

What Gets Created​

  1. IntuitOAuth table with encrypted token storage
  2. Unique index on realmId (company ID)
  3. Index on realmId for fast lookups
  4. Timestamp fields for tracking

Database Security​

  • βœ… Tokens encrypted with AES-256-CBC
  • βœ… Encryption key stored in environment variables
  • βœ… Only application can decrypt tokens
  • βœ… No tokens in API responses
  • βœ… Automatic cleanup of expired records (optional)

Implementation Details​

Architecture Overview​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Admin │────────▢│ OAuth Flow │────────▢│ Intuit β”‚
β”‚ Dashboard β”‚ β”‚ β”‚ β”‚ OAuth β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Database β”‚ β”‚ QuickBooks β”‚
β”‚ (Tokens) β”‚ β”‚ API β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β–²
β”‚ β”‚
β–Ό β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ Auto Token β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ Refresh β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Files Created​

Core Utilities​

src/utils/intuitOAuth.ts - Token management

  • encrypt(text) - AES-256-CBC encryption
  • decrypt(text) - Decrypt stored tokens
  • storeIntuitTokens() - Save/update tokens
  • getValidAccessToken() - Get valid token (auto-refreshes)
  • isIntuitConnected() - Check connection status
  • getIntuitOAuthStatus() - Get detailed status

src/utils/intuitPayments.ts - Payment processing

  • processIntuitPayment() - Process credit card payment
  • createIntuitCustomer() - Create customer in QuickBooks
  • createIntuitInvoice() - Generate invoice

API Routes​

src/app/api/admin/intuit/auth/route.ts

  • Initiates OAuth 2.0 flow
  • Generates CSRF protection state
  • Redirects to Intuit authorization

src/app/api/admin/intuit/callback/route.ts

  • Handles OAuth callback
  • Validates CSRF state
  • Exchanges code for tokens
  • Stores encrypted tokens

src/app/api/admin/intuit/status/route.ts

  • Returns connection status
  • Shows token expiration
  • Company/realm ID info

src/app/api/admin/intuit/refresh/route.ts

  • Manual token refresh endpoint
  • For testing and troubleshooting

UI Components​

src/components/IntuitOAuthSection.tsx

  • Beautiful admin UI
  • Connection status display
  • Connect/Reconnect buttons
  • Real-time token expiration
  • Success/error messaging

OAuth Flow Sequence​

1. Admin clicks "Connect to QuickBooks"
↓
2. App redirects to Intuit (with state for CSRF)
↓
3. User logs in and authorizes on Intuit's page
↓
4. Intuit redirects back with authorization code
↓
5. App validates state (CSRF protection)
↓
6. App exchanges code for access + refresh tokens
↓
7. Tokens encrypted with AES-256-CBC
↓
8. Stored in CockroachDB IntuitOAuth table
↓
9. Admin dashboard shows "Connected" βœ…

Automatic Token Refresh​

During Checkout or API Call:
1. App calls getValidAccessToken()
↓
2. Check if token expires in < 5 minutes
↓
3. If expiring: Use refresh token to get new tokens
↓
4. Encrypt and update database
↓
5. Return valid access token
↓
6. Payment/API call proceeds normally βœ…

Benefits:

  • Zero downtime
  • No user intervention needed
  • Automatic before expiration
  • Transparent to checkout flow

Token Lifecycle​

Token TypeLifetimeRefresh Strategy
Access Token1 hourAuto-refresh at 55 minutes
Refresh Token100 daysManual reconnection needed
CSRF State10 minutesSingle use, then deleted

Admin Dashboard Guide​

Accessing the Integration​

  1. Log in to your admin account
  2. Navigate to /admin (Admin Dashboard)
  3. Look for "Intuit QuickBooks Integration" section at the top

Before Connecting​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ’š Intuit QuickBooks Integration β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ Connect your Intuit QuickBooks account to enable payment β”‚
β”‚ processing and automated invoicing. β”‚
β”‚ β”‚
β”‚ [⚑ Connect to QuickBooks] [ℹ️ View Documentation] β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

After Successfully Connecting​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ’š Intuit QuickBooks Integration β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ βœ… Success! Successfully connected to Intuit QuickBooks! β”‚
β”‚ β”‚
β”‚ Status Company ID β”‚
β”‚ 🟒 Connected 1234567890 β”‚
β”‚ β”‚
β”‚ Token Expires Connected Since β”‚
β”‚ Oct 11, 2025, 3:45 PM Oct 10, 2025, 2:45 PM β”‚
β”‚ β”‚
β”‚ [πŸ”„ Refresh Token] [Reconnect] [ℹ️ View Documentation] β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

How to Connect​

  1. Click "Connect to QuickBooks" button
  2. You'll be redirected to Intuit's authorization page
  3. Log in to your Intuit account
  4. Select the QuickBooks company to connect
  5. Review the permissions requested
  6. Click "Authorize" to grant access
  7. You'll be automatically redirected back to admin dashboard
  8. Success message appears and status updates to "Connected"

Available Actions​

πŸ”„ Refresh Token​

When to use:

  • See "Expired" status
  • Manually force a token refresh
  • Testing purposes

How to use:

  1. Click "Refresh Token" button
  2. Wait for animation (1-2 seconds)
  3. Check for success message
  4. Status updates to "Connected"

πŸ”„ Reconnect​

When to use:

  • Refresh token expired (after 100 days)
  • Connect different QuickBooks company
  • Update permissions/scopes
  • Fix connection issues

How to use:

  • Click "Reconnect" button
  • Complete OAuth flow again
  • Old connection replaced with new one

ℹ️ View Documentation​

Opens official Intuit OAuth 2.0 documentation in new tab.

Status Indicators​

IndicatorMeaningAction Required
🟒 ConnectedEverything workingNone
πŸ”΄ ExpiredToken needs refreshClick "Refresh Token" or "Reconnect"

Information Displayed​

  • Status: Current connection state (Connected/Expired)
  • Company ID: Your QuickBooks company/realm ID
  • Token Expires: When current access token expires
  • Connected Since: When you first connected

What This Enables​

Once connected, your application can:

βœ… Process Payments

  • Accept credit card payments
  • Process transactions securely
  • Handle refunds

βœ… Manage Invoices

  • Create invoices automatically
  • Send invoices to customers
  • Track invoice status

βœ… Sync Customers

  • Create customer records in QuickBooks
  • Keep customer data synchronized
  • Access customer payment history

βœ… Financial Reporting

  • Track sales and revenue
  • Generate financial reports
  • Monitor business performance

Usage in Code​

Getting a Valid Access Token​

The system automatically handles token refresh. Use this in your payment/API code:

import { getValidAccessToken } from "@/utils/intuitOAuth";

// This function automatically refreshes expired tokens
const accessToken = await getValidAccessToken();

if (!accessToken) {
throw new Error("Intuit OAuth not configured");
}

// Use the access token for API calls

Processing Payments​

Example: Checkout Flow​

import { processIntuitPayment } from "@/utils/intuitPayments";

export async function handleCheckout(orderData) {
try {
// Token refresh happens automatically inside this function
const result = await processIntuitPayment({
amount: orderData.total,
currency: "USD",
card: {
number: orderData.cardNumber,
expMonth: orderData.expMonth,
expYear: orderData.expYear,
cvc: orderData.cvc,
name: orderData.cardholderName,
address: {
streetAddress: orderData.address,
city: orderData.city,
region: orderData.state,
country: "US",
postalCode: orderData.zip,
},
},
});

if (result.success) {
return {
success: true,
transactionId: result.transactionId,
};
} else {
return {
success: false,
error: result.error,
};
}
} catch (error) {
console.error("Checkout failed:", error);
return {
success: false,
error: "Payment processing failed",
};
}
}

Creating Customers​

import { createIntuitCustomer } from "@/utils/intuitPayments";

const customer = await createIntuitCustomer({
displayName: "John Doe",
givenName: "John",
familyName: "Doe",
primaryEmailAddr: { address: "john@example.com" },
primaryPhone: { freeFormNumber: "(555) 123-4567" },
});

if (customer.success) {
console.log("Customer created:", customer.customerId);
}

Creating Invoices​

import { createIntuitInvoice } from "@/utils/intuitPayments";

const invoice = await createIntuitInvoice({
customerRef: { value: "123" }, // QuickBooks customer ID
line: [
{
amount: 99.99,
detailType: "SalesItemLineDetail",
salesItemLineDetail: {
itemRef: { value: "1", name: "Cricket Lane Rental" },
qty: 2,
unitPrice: 49.99,
},
},
],
});

if (invoice.success) {
console.log("Invoice created:", invoice.invoiceId);
}

Checking Connection Status​

import { isIntuitConnected, getIntuitOAuthStatus } from "@/utils/intuitOAuth";

// Simple check
const connected = await isIntuitConnected();
if (!connected) {
// Redirect to admin to connect
}

// Detailed status
const status = await getIntuitOAuthStatus();
if (status && !status.isExpired) {
// Process payment
}

Security Features​

Encryption​

AES-256-CBC Encryption

  • Access tokens encrypted at rest
  • Refresh tokens encrypted at rest
  • Encryption key stored in environment variables
  • Tokens never exposed in API responses
// Encryption implementation
const ALGORITHM = "aes-256-cbc";
const key = crypto.createHash("sha256").update(ENCRYPTION_KEY).digest();
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);

CSRF Protection​

  • State parameter generated for each OAuth flow
  • Stored in secure HTTP-only cookie
  • Validated on callback
  • Single-use (deleted after validation)
  • 10-minute expiration

Automatic Token Refresh​

  • Tokens refresh 5 minutes before expiration
  • Uses refresh token automatically
  • Transparent to application code
  • No user intervention needed
  • Zero downtime

Access Control​

  • All OAuth endpoints require admin authentication
  • Regular users cannot access OAuth settings
  • Admin-only routes protected by middleware
  • Database access restricted to application

Secure Storage​

  • Tokens stored in CockroachDB
  • Database connection encrypted (SSL/TLS)
  • Environment variables for sensitive data
  • No hardcoded credentials
  • Production-grade security

HTTPS Enforcement​

  • Required in production
  • Secure cookie settings
  • SSL/TLS for all API calls
  • Man-in-the-middle prevention

PCI Compliance​

  • No card data stored in database
  • Tokens used for QuickBooks API only
  • PCI-compliant payment processing
  • Secure tokenization support

Troubleshooting​

Common Issues​

"Intuit OAuth not configured"​

Cause: Missing or incorrect environment variables

Solution:

  1. Check all 4 required environment variables are set:
    • INTUIT_CLIENT_ID
    • INTUIT_CLIENT_SECRET
    • INTUIT_REDIRECT_URI
    • INTUIT_ENCRYPTION_KEY
  2. Verify values are correct (no typos)
  3. Restart your application after adding variables
  4. Check .env.local file is in project root

"invalid_state" Error​

Cause: CSRF protection working (good!) but state mismatch

Solution:

  1. Clear browser cookies
  2. Try OAuth flow again
  3. Ensure cookies are enabled in browser
  4. Check cookie settings if behind proxy

"Token exchange failed"​

Cause: Problem exchanging authorization code for tokens

Solution:

  1. Verify INTUIT_CLIENT_SECRET is correct
  2. Ensure INTUIT_REDIRECT_URI matches exactly in Intuit app settings
  3. Check authorization code hasn't expired (they're short-lived)
  4. Try connecting again

"Token refresh failed"​

Cause: Refresh token expired or invalid

Solution:

  1. Refresh tokens expire after 100 days
  2. Click "Reconnect" button in admin dashboard
  3. Complete OAuth flow again
  4. New tokens will be stored

"Can't reach database server"​

Cause: Database connection issue

Solution:

  1. Check DATABASE_URL is correct
  2. Verify database is running
  3. Check network/firewall settings
  4. Ensure SSL is configured if required

Connection Shows "Expired"​

Expected behavior if:

  • Access tokens expire after 1 hour
  • System should auto-refresh

If it stays expired:

  1. Click "Refresh Token" button
  2. Check application logs for errors
  3. If refresh fails, click "Reconnect"
  4. Verify refresh token hasn't expired (100 days)

Payments Fail After Scope Change​

Cause: Changed scopes but didn't reconnect

Solution:

  1. Any scope change requires reconnection
  2. Go to admin dashboard
  3. Click "Reconnect"
  4. Authorize with new scopes
  5. Test payment processing

Testing in Sandbox​

Intuit provides sandbox environment for testing:

  1. In Intuit Developer Portal, toggle to "Sandbox"
  2. Create test company
  3. Use sandbox credentials in .env.local
  4. Test all features without real money
  5. When ready, switch to "Production" toggle
  6. Update to production credentials

Logging and Debugging​

Enable detailed logging:

// In your API routes or utilities
console.log("OAuth status:", await getIntuitOAuthStatus());
console.log("Access token valid:", !!(await getValidAccessToken()));

Check token expiration:

-- In your database
SELECT id, realmId, expiresAt, createdAt, updatedAt
FROM IntuitOAuth
ORDER BY updatedAt DESC
LIMIT 1;

Tokens appear encrypted (this is correct):

accessToken: "a1b2c3:d4e5f6g7h8i9..." (encrypted)
refreshToken: "x1y2z3:a4b5c6d7e8f9..." (encrypted)

API Reference​

OAuth Endpoints​

GET /api/admin/intuit/auth​

Description: Initiates OAuth 2.0 flow

Authentication: Admin required

Response: Redirects to Intuit authorization page

Query Parameters: None

Example:

// User clicks "Connect to QuickBooks"
window.location.href = "/api/admin/intuit/auth";

GET /api/admin/intuit/callback​

Description: Handles OAuth callback from Intuit

Authentication: Admin required

Query Parameters:

  • code - Authorization code from Intuit
  • state - CSRF protection state
  • realmId - QuickBooks company ID
  • error - Error message if authorization failed

Response: Redirects to admin dashboard with status

Example:

https://yourapp.com/api/admin/intuit/callback?
code=L123456789...&
realmId=9876543210...&
state=abc123...

GET /api/admin/intuit/status​

Description: Gets current OAuth connection status

Authentication: Admin required

Response:

{
"connected": true,
"realmId": "9876543210",
"expiresAt": "2025-10-11T15:45:00.000Z",
"isExpired": false,
"connectedAt": "2025-10-10T14:45:00.000Z",
"lastUpdated": "2025-10-11T14:45:00.000Z"
}

Example:

const response = await fetch("/api/admin/intuit/status");
const status = await response.json();
console.log("Connected:", status.connected);

POST /api/admin/intuit/refresh​

Description: Manually triggers token refresh

Authentication: Admin required

Response:

{
"success": true,
"message": "Token refreshed successfully"
}

Example:

const response = await fetch("/api/admin/intuit/refresh", {
method: "POST",
});
const result = await response.json();

Utility Functions​

getValidAccessToken()​

Returns: Promise<string | null>

Description: Gets valid access token, auto-refreshing if needed

Example:

const token = await getValidAccessToken();
if (token) {
// Use token for API call
}

storeIntuitTokens(realmId, accessToken, refreshToken, expiresIn)​

Parameters:

  • realmId (string) - QuickBooks company ID
  • accessToken (string) - Access token from Intuit
  • refreshToken (string) - Refresh token from Intuit
  • expiresIn (number) - Seconds until expiration

Returns: Promise<void>

Description: Stores or updates encrypted OAuth tokens


isIntuitConnected()​

Returns: Promise<boolean>

Description: Checks if OAuth is configured and connected


getIntuitOAuthStatus()​

Returns: Promise<object | null>

Description: Gets detailed OAuth status information


processIntuitPayment(paymentRequest)​

Parameters:

  • paymentRequest (object)
    • amount (number) - Payment amount
    • currency (string) - Currency code (default: "USD")
    • card (object) - Card details
      • number, expMonth, expYear, cvc, name
      • address (optional)

Returns: Promise<PaymentResponse>

Description: Processes payment through QuickBooks Payments API


createIntuitCustomer(customer)​

Parameters:

  • customer (object)
    • displayName (string)
    • givenName, familyName (optional)
    • primaryEmailAddr, primaryPhone (optional)

Returns: Promise<{success, customerId?, error?}>

Description: Creates customer in QuickBooks


createIntuitInvoice(invoice)​

Parameters:

  • invoice (object)
    • customerRef (object) - {value: customerId}
    • line (array) - Invoice line items

Returns: Promise<{success, invoiceId?, error?}>

Description: Creates invoice in QuickBooks


Production Deployment​

Pre-Deployment Checklist​

Intuit Configuration​

  • Create production app in Intuit Developer Portal
  • Add production redirect URI
  • Enable required scopes
  • Note production Client ID and Secret
  • Submit for production approval (if needed)

Environment Variables​

  • Set INTUIT_CLIENT_ID (production)
  • Set INTUIT_CLIENT_SECRET (production)
  • Set INTUIT_REDIRECT_URI (production domain)
  • Generate new INTUIT_ENCRYPTION_KEY (different from dev)
  • Verify INTUIT_OAUTH_SCOPE is correct

Database​

  • Run migrations in production
  • Verify IntuitOAuth table created
  • Test database connectivity
  • Set up database backups

Security​

  • HTTPS enabled and enforced
  • Environment variables secured
  • Database connections encrypted
  • Admin access restricted
  • Logs don't expose secrets

Testing​

  • Test OAuth flow in production
  • Verify token refresh works
  • Test payment processing
  • Test error handling
  • Monitor for issues

Production Environment Variables​

# Production values (example)
INTUIT_CLIENT_ID="prod_abc123..."
INTUIT_CLIENT_SECRET="prod_secret_xyz..."
INTUIT_REDIRECT_URI="https://gullysports.com/api/admin/intuit/callback"
INTUIT_ENCRYPTION_KEY="<unique-production-key-64-chars>"
INTUIT_OAUTH_SCOPE="com.intuit.quickbooks.accounting com.intuit.quickbooks.payment"

Deployment Platforms​

Vercel​

Add environment variables in Vercel dashboard:

  1. Go to Project Settings
  2. Navigate to Environment Variables
  3. Add each variable
  4. Deploy

AWS / Other Platforms​

Use platform-specific secret management:

  • AWS Systems Manager Parameter Store
  • AWS Secrets Manager
  • Kubernetes Secrets
  • Platform environment variables

Monitoring​

Track these metrics:

  • OAuth connection status
  • Token refresh success rate
  • Payment processing errors
  • API response times
  • Failed authorization attempts

Set up alerts for:

  • Token refresh failures
  • Payment processing errors
  • Database connectivity issues
  • High error rates

Maintenance​

Regular Tasks​

Weekly:

  • Review error logs
  • Check token refresh logs
  • Monitor payment success rates

Monthly:

  • Review connection status
  • Update dependencies
  • Check for Intuit API updates

Quarterly:

  • Audit OAuth scopes (least privilege)
  • Review security settings
  • Update documentation
  • Performance optimization

Token Lifecycle Management​

Refresh tokens expire after 100 days:

  1. Set up reminder 80 days after connection
  2. Notify admin to reconnect
  3. Schedule reconnection before expiration
  4. Monitor for expired connections

Backup and Recovery​

Backup OAuth Configuration:

  • Export IntuitOAuth table regularly
  • Store encrypted backups securely
  • Document recovery procedures

Recovery Process:

  1. Restore database from backup
  2. Verify environment variables
  3. Test OAuth connection
  4. Refresh tokens if needed
  5. Validate payment processing

Additional Resources​

Intuit Documentation​

OAuth 2.0 Standards​

Security Resources​


Support​

Need Help?​

  1. Check this guide - Most questions are answered here
  2. Review Intuit's documentation - Official API docs
  3. Check application logs - Look for error messages
  4. Test in sandbox - Before production troubleshooting

Found a Bug?​

  1. Check if it's in the logs
  2. Verify environment variables
  3. Test in isolation
  4. Document steps to reproduce
  5. Check if known issue

For Intuit API Issues​


Summary​

What You Get​

βœ… Complete OAuth 2.0 integration with Intuit QuickBooks
βœ… Automatic token management with refresh
βœ… Secure encrypted storage with AES-256-CBC
βœ… Beautiful admin interface for easy management
βœ… Payment processing capability
βœ… Invoice generation and management
βœ… Customer sync functionality
βœ… Production-ready code with error handling
βœ… Comprehensive documentation and examples

Implementation Status​

Status: βœ… Complete and Production Ready
Security Level: Enterprise-grade
Documentation: Comprehensive
Code Quality: Production-ready
Testing: Sandbox and production ready

Next Steps​

  1. βœ… Complete Intuit Developer Portal setup
  2. βœ… Add environment variables
  3. βœ… Run database migration
  4. βœ… Connect QuickBooks in admin dashboard
  5. βœ… Test in sandbox mode
  6. βœ… Integrate with checkout flow
  7. βœ… Deploy to production

Estimated Setup Time: 20 minutes
Support: This comprehensive guide + Intuit docs


πŸŽ‰ You're ready to process payments with QuickBooks!

For questions or issues, refer to the Troubleshooting section or Intuit's support resources.