Skip to content
Back to skills

Node Backend

ASecurity

Build Node.js backends for BigCommerce apps — Express/Fastify servers, OAuth handling, JWT verification, API proxy, webhook processing, session management, and deployment. Use when building the server-side component of BigCommerce apps.

  • 39 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 29, 2026
ai-agentstypescriptrustgonodeexpressawsgitapidatabasebackend

Works with

  • cli
  • api

Security analysis

A100/100

Scanned May 29, 2026

npx -y skills add OrcaQubits/agentic-commerce-skills-plugins --skill node-backend --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Node Backend?

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

Security grade badge for Node Backend
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/orcaqubits-node-backend/badge)](https://www.skillsdirectory.com/skills/orcaqubits-node-backend)

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: node-backend
description: >
  Build Node.js backends for BigCommerce apps — Express/Fastify servers, OAuth
  handling, JWT verification, API proxy, webhook processing, session management,
  and deployment. Use when building the server-side component of BigCommerce
  apps.
---

# Node.js Backend for BigCommerce Apps

## Before writing code

**Fetch live docs**:
1. Web-search `site:developer.bigcommerce.com apps guide` for app development patterns
2. Fetch `https://expressjs.com/` or `https://fastify.dev/` for framework docs
3. Web-search `bigcommerce node sample app github` for official sample apps

## App Server Architecture

### Typical Stack

```
BigCommerce Admin (iframe)
    ↓ OAuth flow / Load callback
Your Node.js Server (Express/Fastify)
    ↓ API calls
BigCommerce REST/GraphQL APIs
    ↓ Webhooks
Your Webhook Handler
```

### Project Structure

```
bc-app/
├── src/
│   ├── index.ts              # Server entry point
│   ├── routes/
│   │   ├── auth.ts           # OAuth callbacks (install, load, uninstall)
│   │   ├── api.ts            # App API routes
│   │   └── webhooks.ts       # Webhook handlers
│   ├── services/
│   │   ├── bigcommerce.ts    # BigCommerce API client
│   │   └── store.ts          # Store/token management
│   ├── middleware/
│   │   ├── auth.ts           # Authentication middleware
│   │   └── verify.ts         # JWT/webhook verification
│   └── lib/
│       ├── jwt.ts            # JWT utilities
│       └── db.ts             # Database connection
├── .env                      # Environment variables
├── package.json
└── tsconfig.json
```

## OAuth Implementation

### Install Callback

```typescript
// routes/auth.ts
app.get('/auth/install', async (req, res) => {
  const { code, scope, context } = req.query;

  // Exchange code for permanent token
  const tokenResponse = await fetch('https://login.bigcommerce.com/oauth2/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: process.env.BC_CLIENT_ID,
      client_secret: process.env.BC_CLIENT_SECRET,
      code,
      scope,
      grant_type: 'authorization_code',
      redirect_uri: process.env.BC_AUTH_CALLBACK,
      context,
    }),
  });

  const { access_token, user, context: storeContext } = await tokenResponse.json();
  const storeHash = storeContext.split('/')[1];

  // Store token securely
  await saveStoreToken(storeHash, access_token, user);

  // Return app UI
  res.send('<html>App installed successfully!</html>');
});
```

### Load Callback

```typescript
app.get('/auth/load', async (req, res) => {
  const signedPayload = req.query.signed_payload_jwt as string;

  // Verify JWT
  const decoded = verifyJwt(signedPayload, process.env.BC_CLIENT_SECRET!);
  const storeHash = decoded.sub.split('/')[1];
  const userId = decoded.user.id;

  // Load store token
  const token = await getStoreToken(storeHash);

  // Render app UI
  res.send(renderApp(storeHash, userId));
});
```

### Uninstall Callback

```typescript
app.get('/auth/uninstall', async (req, res) => {
  const signedPayload = req.query.signed_payload_jwt as string;
  const decoded = verifyJwt(signedPayload, process.env.BC_CLIENT_SECRET!);
  const storeHash = decoded.sub.split('/')[1];

  // Clean up stored data
  await deleteStoreData(storeHash);

  res.status(200).send('OK');
});
```

## JWT Verification

```typescript
import jwt from 'jsonwebtoken';

function verifyJwt(token: string, secret: string) {
  return jwt.verify(token, secret, {
    algorithms: ['HS256'],
    audience: process.env.BC_CLIENT_ID,
  });
}
```

## BigCommerce API Client

### Typed HTTP Client

```typescript
class BigCommerceClient {
  constructor(
    private storeHash: string,
    private accessToken: string,
  ) {}

  private async request<T>(path: string, options?: RequestInit): Promise<T> {
    const url = `https://api.bigcommerce.com/stores/${this.storeHash}${path}`;
    const response = await fetch(url, {
      ...options,
      headers: {
        'X-Auth-Token': this.accessToken,
        'Content-Type': 'application/json',
        Accept: 'application/json',
        ...options?.headers,
      },
    });

    if (response.status === 429) {
      const retryAfter = response.headers.get('X-Rate-Limit-Time-Reset-Ms');
      // Implement backoff
    }

    if (!response.ok) {
      throw new ApiError(response.status, await response.text());
    }

    return response.json();
  }

  async getProducts(params?: Record<string, string>) {
    const query = new URLSearchParams(params).toString();
    return this.request(`/v3/catalog/products?${query}`);
  }

  async getOrder(orderId: number) {
    return this.request(`/v2/orders/${orderId}`);
  }
}
```

## Webhook Handling

```typescript
app.post('/webhooks/orders', async (req, res) => {
  // Verify webhook (check custom header)
  const secret = req.headers['x-webhook-secret'];
  if (secret !== process.env.WEBHOOK_SECRET) {
    return res.status(401).send('Unauthorized');
  }

  // Acknowledge immediately
  res.status(200).send('OK');

  // Process asynchronously
  const { scope, data, store_id } = req.body;
  await processOrderEvent(store_id, data.id, scope);
});
```

## Session Management

### For Multi-Store Apps

Store sessions with store hash context:
- Use Redis or database-backed sessions
- Associate session with `storeHash` and `userId`
- Validate session on every request

### Cookie Security

```typescript
app.use(session({
  secret: process.env.SESSION_SECRET!,
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: true,        // HTTPS only
    httpOnly: true,      // No JS access
    sameSite: 'none',    // Required for iframe embedding
    maxAge: 24 * 60 * 60 * 1000,
  },
}));
```

Note: `sameSite: 'none'` is required because BigCommerce apps load in an iframe.

## Error Handling

```typescript
// Global error handler
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  console.error('Unhandled error:', err);
  res.status(500).json({ error: 'Internal server error' });
});

// API error class
class ApiError extends Error {
  constructor(public statusCode: number, message: string) {
    super(message);
  }
}
```

## Deployment

### Platform Options

| Platform | Pros | Setup |
|----------|------|-------|
| Vercel | Easy, auto-scaling, edge functions | `vercel deploy` |
| Railway | Simple, DB support | `railway deploy` |
| Render | Free tier, managed services | Git push |
| AWS Lambda | Serverless, pay-per-use | SAM/CDK |
| Heroku | Classic PaaS | `git push heroku` |

### Environment Variables

Always set via platform's secret management — never in code:
```
BC_CLIENT_ID=xxx
BC_CLIENT_SECRET=xxx
BC_AUTH_CALLBACK=https://your-app.com/auth/install
BC_LOAD_CALLBACK=https://your-app.com/auth/load
BC_UNINSTALL_CALLBACK=https://your-app.com/auth/uninstall
SESSION_SECRET=xxx
WEBHOOK_SECRET=xxx
DATABASE_URL=xxx
```

## Best Practices

- Use TypeScript for type safety across API interactions
- Verify JWTs on every callback — never trust unsigned payloads
- Store tokens encrypted in database, not in memory or sessions
- Handle rate limits with exponential backoff
- Process webhooks asynchronously — acknowledge with 200 immediately
- Use `sameSite: 'none'` + `secure: true` cookies for iframe embedding
- Implement health check endpoints for monitoring
- Log API errors but never log tokens or secrets
- Use connection pooling for database connections

Fetch the BigCommerce app development guide and Node.js framework docs for exact callback parameters, JWT structure, and deployment patterns before implementing.

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…