Skip to main content
POST
/
api
/
reddit
/
oauth
/
exchange
Reddit OAuth Token Exchange
curl --request POST \
  --url https://api.example.com/api/reddit/oauth/exchange \
  --header 'Content-Type: application/json' \
  --data '
{
  "code": "<string>",
  "reconnect_account_id": "<string>"
}
'
{
  "ok": true,
  "account": {
    "account.id": "<string>",
    "account.username": "<string>"
  },
  "error": "<string>",
  "details": "<string>"
}

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MatthewSabia1/SubPirate-Pro/llms.txt

Use this file to discover all available pages before exploring further.

Overview

This endpoint completes the Reddit OAuth 2.0 flow by exchanging an authorization code for access and refresh tokens. The tokens are encrypted using AES-256-GCM and stored securely in the database.

Authentication

Requires valid Supabase JWT token in Authorization header:
Authorization: Bearer <supabase_access_token>

Request Body

code
string
required
The authorization code received from Reddit OAuth callback
reconnect_account_id
string
Optional UUID of an existing reddit_accounts row to reconnect. If provided, the endpoint verifies that the OAuth user matches the stored reddit_user_id before updating tokens.

Response

ok
boolean
Indicates successful token exchange and storage
account
object
The connected Reddit account details
account.id
string
UUID of the reddit_accounts row
account.username
string
Reddit username (e.g. “spez”)

Token Encryption

All Reddit tokens are encrypted at rest using AES-256-GCM encryption:
  1. Encryption Key: Must be set in TOKEN_ENCRYPTION_KEY environment variable (base64-encoded 32-byte key)
  2. IV Generation: Random 12-byte IV generated per encryption
  3. Storage Format: v1:<iv_base64>:<tag_base64>:<ciphertext_base64>
  4. Database Storage: Encrypted tokens stored in reddit_account_tokens table:
    • access_token_enc - Encrypted Reddit access token
    • refresh_token_enc - Encrypted Reddit refresh token
The encryption is handled by the encryptString() function in server.js:297-311.

Subscription Requirements

This endpoint enforces subscription-based account limits:
  • Free tier: No Reddit accounts allowed
  • Paid tiers: Max accounts determined by plan_definitions.max_reddit_accounts
  • Returns 403 with subscription_required if user has no active subscription
  • Returns 403 with quota_exceeded if account limit reached

Error Responses

error
string
Human-readable error message
details
string
Additional error context (may be null)

Common Error Codes

StatusErrorDescription
400Missing OAuth codeNo code provided in request body
400Invalid reconnect account idreconnect_account_id is not a valid UUID
400Reconnect account not found for this userSpecified account doesn’t exist or doesn’t belong to user
403subscription_requiredUser has no active subscription
403quota_exceededUser has reached their Reddit account limit
409Reconnect requires the same Reddit accountOAuth username doesn’t match the account being reconnected
500Reddit OAuth is not configuredREDDIT_CLIENT_ID or REDDIT_CLIENT_SECRET not set
500Failed to encrypt Reddit tokensTOKEN_ENCRYPTION_KEY missing or invalid
502Invalid token response from RedditReddit token exchange failed
502Invalid user response from RedditReddit /api/v1/me request failed

Example Request

curl -X POST https://api.subpirateapp.com/api/reddit/oauth/exchange \
  -H "Authorization: Bearer eyJhbGc..." \
  -H "Content-Type: application/json" \
  -d '{
    "code": "abc123xyz"
  }'

Example Success Response

{
  "ok": true,
  "account": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "username": "example_user"
  }
}

Example Error Response

{
  "error": "quota_exceeded",
  "feature": "reddit_accounts",
  "limit": 3,
  "upgrade_required": true,
  "message": "You've reached your limit of 3 Reddit accounts. Upgrade for more."
}

Implementation Details

OAuth Flow

  1. Code Exchange: Calls https://www.reddit.com/api/v1/access_token with Basic auth (client_id:client_secret)
  2. User Fetch: Calls https://oauth.reddit.com/api/v1/me with access token
  3. Account Upsert: Uses upsert_reddit_account_with_limit stored procedure to enforce quota
  4. Token Encryption: Encrypts access_token and refresh_token using AES-256-GCM
  5. Token Storage: Upserts to reddit_account_tokens with 3 retry attempts
  6. Fallback Recovery: On RLS/FK errors, falls back to service role client

Retry Logic

Token upsert includes retry logic for transient failures (server.js:420-442):
  • Max attempts: 3
  • Retry conditions: PostgreSQL error codes 23503, 40001, 40P01 or RLS policy violations
  • Backoff: Linear (150ms, 300ms, 450ms)
  • Verification: After failure, verifies token row exists before returning error

Reconnect Flow

When reconnect_account_id is provided:
  1. Normalizes UUID (accepts both dashed and compact formats)
  2. Verifies account exists and belongs to user
  3. Validates OAuth username matches stored reddit_user_id
  4. Updates existing account row instead of creating new one
  5. Returns 409 conflict if usernames don’t match
See executeRedditOAuthExchangeFlow() in api/_lib/redditOAuthExchangeFlow.js:64-227 for full implementation.