Skip to main content

Authorization and OAuth Scopes

Learn how to use OAuth scopes to control access to Trading Card API resources with fine-grained permissions.

What Are OAuth Scopes?

OAuth scopes are permissions that define what actions an application can perform on behalf of a user. They implement the principle of least privilege by allowing you to request only the permissions your application actually needs.

When you authenticate with the Trading Card API using OAuth 2.0, you specify which scopes your application requires. The API then grants your access token permissions based on those scopes.

Why Scopes Matter

  • Security - Limit the blast radius if a token is compromised
  • User Trust - Users can see exactly what permissions they're granting
  • Compliance - Meet security requirements for handling sensitive data
  • Flexibility - Different clients (public apps, admin tools) need different permissions

Available Scopes

The Trading Card API supports five OAuth scopes for fine-grained access control:

Read Scopes (Data Access)

read:published

Access published cards, sets, and other resources only.

Use this scope for:

  • Public-facing applications
  • Read-only card browsers
  • Public API integrations
  • Applications that don't need access to draft content

Example use case: A public website displaying trading card information to visitors.

{
"scope": "read:published"
}

read:draft

Access draft and unpublished content in addition to published content.

Use this scope for:

  • Content management systems
  • Preview and staging environments
  • Editorial workflows
  • Applications that need to work with unpublished data

Example use case: A content management dashboard where editors prepare card data before publishing.

{
"scope": "read:draft"
}

read:all-status

Access all content regardless of publication status (published, draft, archived, etc.).

Use this scope for:

  • Administrative tools
  • Data migration applications
  • Comprehensive reporting systems
  • Applications needing full data visibility

Example use case: An admin dashboard showing all cards including drafts, published, and archived items.

{
"scope": "read:all-status"
}
Read Scope Comparison
  • read:published → See published content only
  • read:draft → See published + draft content
  • read:all-status → See all content (published, draft, archived, etc.)

Choose the minimum scope needed for your use case.

Write Scope

write

Create and update resources (POST, PATCH operations).

Allows:

  • Creating new cards, sets, players, teams, etc.
  • Updating existing resources
  • Uploading card images
  • Modifying metadata

Does NOT allow:

  • Deleting resources (requires delete scope)
  • Changing publication status (requires appropriate read scope)

Example use case: A collection management app where users add and edit their card collections.

{
"scope": "read:published write"
}

Delete Scope

delete

Delete resources (DELETE operations).

Allows:

  • Soft deleting resources
  • Permanently deleting resources
  • Removing card images

Requires:

  • Usually combined with read and write scopes for full CRUD operations

Example use case: An admin tool with full data management capabilities.

{
"scope": "read:all-status write delete"
}
Security Notice

The delete scope is powerful and should be requested only by trusted applications with administrative purposes. Most public applications should NOT request this scope.

Understanding Status-Based Access Control

One of the key features of the Trading Card API's scope system is status-based filtering. Different scopes automatically filter the data you can access based on the publication status of resources.

How It Works

ScopePublished CardsDraft CardsArchived Cards
read:published✅ Yes❌ No❌ No
read:draft✅ Yes✅ Yes❌ No
read:all-status✅ Yes✅ Yes✅ Yes

This filtering happens automatically - you don't need to add status filters to your queries. The API respects your token's scopes and only returns resources you're permitted to see.

Example Scenarios

Public App (read:published):

// With read:published scope, this query returns only published cards
const cards = await client.cards.list({
'filter[set_id]': 'some-set-id'
});
// Result: Only published cards from the set

Admin Tool (read:all-status):

// With read:all-status scope, same query returns ALL cards
const cards = await client.cards.list({
'filter[set_id]': 'some-set-id'
});
// Result: Published, draft, AND archived cards from the set

Scope Combinations

Most real-world applications need multiple scopes. Here are common combinations:

Public Read-Only Application

{
"scope": "read:published"
}

Perfect for:

  • Public card browsers
  • Market price displays
  • Collection showcases
  • Public APIs

Collection Management App

{
"scope": "read:published write"
}

Perfect for:

  • User collection tracking
  • Personal collection apps
  • Portfolio management
  • Wishlist applications

Content Management System

{
"scope": "read:draft write"
}

Perfect for:

  • Editorial workflows
  • Content preparation
  • Preview systems
  • Staging environments

Administrative Dashboard

{
"scope": "read:all-status write delete"
}

Perfect for:

  • Admin panels
  • Data management tools
  • Moderation systems
  • Full CRUD applications

Data Migration Tool

{
"scope": "read:all-status write"
}

Perfect for:

  • Importing data
  • Syncing systems
  • Bulk operations
  • Data transformations

Requesting Scopes

When authenticating with OAuth 2.0, specify your required scopes in the token request:

OAuth 2.0 Client Credentials Flow

PHP

<?php

require_once 'vendor/autoload.php';

use TradingCardAPI\Client;

// Initialize client with specific scopes
$client = new Client([
'clientId' => getenv('TRADING_CARD_API_CLIENT_ID'),
'clientSecret' => getenv('TRADING_CARD_API_CLIENT_SECRET'),
'baseUrl' => 'https://api.tradingcardapi.com',
'scopes' => ['read:published', 'write'] // Request specific scopes
]);

// The client will automatically request these scopes when obtaining a token
$cards = $client->cards()->list();

JavaScript

const TradingCardAPI = require('trading-card-api');

// Initialize client with specific scopes
const client = new TradingCardAPI({
clientId: process.env.TRADING_CARD_API_CLIENT_ID,
clientSecret: process.env.TRADING_CARD_API_CLIENT_SECRET,
baseUrl: 'https://api.tradingcardapi.com',
scopes: ['read:published', 'write'] // Request specific scopes
});

// The client will automatically request these scopes when obtaining a token
const cards = await client.cards.list();

Python

import os
from trading_card_api import Client

# Initialize client with specific scopes
client = Client(
client_id=os.getenv('TRADING_CARD_API_CLIENT_ID'),
client_secret=os.getenv('TRADING_CARD_API_CLIENT_SECRET'),
base_url='https://api.tradingcardapi.com',
scopes=['read:published', 'write'] # Request specific scopes
)

# The client will automatically request these scopes when obtaining a token
cards = client.cards.list()

cURL (Manual Token Request)

#!/bin/bash

# Request token with specific scopes
curl -X POST "https://api.tradingcardapi.com/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=read:published write"

# Response includes access_token with the requested scopes
# {
# "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
# "token_type": "Bearer",
# "expires_in": 3600,
# "scope": "read:published write"
# }

Personal Access Tokens (PAT)

When generating a Personal Access Token, you can select which scopes to grant:

  1. Log in to your Trading Card API account
  2. Navigate to Settings → API → Personal Access Tokens
  3. Click Generate New Token
  4. Select scopes from the available options:
    • ☐ read:published
    • ☐ read:draft
    • ☐ read:all-status
    • ☐ write
    • ☐ delete
  5. Click Generate Token
Best Practice

Select only the scopes you actually need. You can always generate a new token with different scopes if your requirements change.

Security Best Practices

1. Request Minimum Required Scopes

Only request the scopes your application actually needs:

// ❌ Bad: Requesting all scopes "just in case"
const client = new TradingCardAPI({
scopes: ['read:all-status', 'write', 'delete']
});

// ✅ Good: Request only what you need
const client = new TradingCardAPI({
scopes: ['read:published'] // Read-only public app
});

2. Use Different Tokens for Different Operations

Create separate tokens/clients with different scopes for different parts of your application:

// Public-facing client (read-only)
const publicClient = new TradingCardAPI({
scopes: ['read:published']
});

// Admin client (full access)
const adminClient = new TradingCardAPI({
scopes: ['read:all-status', 'write', 'delete']
});

// Use the appropriate client for each operation
app.get('/api/cards', async (req, res) => {
const cards = await publicClient.cards.list(); // Use read-only client
res.json(cards);
});

app.delete('/api/cards/:id', async (req, res) => {
await adminClient.cards.delete(req.params.id); // Use admin client
res.sendStatus(204);
});

3. Store Tokens Securely

  • Never commit tokens to version control
  • Use environment variables or secure secret management
  • Rotate tokens regularly
  • Revoke unused tokens
# .env file
TRADING_CARD_API_PUBLIC_TOKEN=token_with_read_published
TRADING_CARD_API_ADMIN_TOKEN=token_with_all_scopes

# .gitignore
.env

4. Handle Scope Errors Gracefully

Always check for and handle insufficient scope errors:

try {
await client.cards.delete(cardId);
} catch (error) {
if (error.status === 403 && error.code === 'insufficient_scope') {
console.error('Token lacks delete scope');
// Show user-friendly message or redirect to upgrade
}
throw error;
}

5. Audit Scope Usage

Regularly review which scopes your tokens have and whether they're still needed:

// Check what scopes your token has
const tokenInfo = await client.auth.introspect();
console.log('Active scopes:', tokenInfo.scope);

// If scopes are too broad, generate a new token with narrower scopes

Choosing the Right Scopes

Use this decision tree to select appropriate scopes:

Do you need to modify data?

No → Use read-only scopes

Yes → Add write scope

Do you need to delete data?

No → Don't request delete

Yes → Add delete scope (admin tools only)

What content do you need to access?

Only published contentread:published

Published + draft contentread:draft

All content (including archived)read:all-status

Common Use Cases

Application TypeRecommended Scopes
Public card browserread:published
User collection trackerread:published write
Content management systemread:draft write
Admin dashboardread:all-status write delete
Data import toolread:all-status write
Analytics/reportingread:all-status
Public API integrationread:published

Troubleshooting Scope Issues

Insufficient Scope Error

Error Response:

{
"errors": [{
"status": "403",
"code": "insufficient_scope",
"title": "Insufficient Scope",
"detail": "The access token does not have the required scope for this operation",
"meta": {
"required_scope": "write",
"current_scopes": ["read:published"]
}
}]
}

Solutions:

  1. Generate a new token with the required scope
  2. Request additional scopes when authenticating
  3. Use a different token that has the necessary permissions

Not Seeing Expected Data

If queries return fewer results than expected, check your scope:

// With read:published scope
const cards = await client.cards.list();
// Returns: 100 published cards

// With read:all-status scope
const cards = await client.cards.list();
// Returns: 150 cards (100 published + 30 draft + 20 archived)

Solution: Ensure your token has the appropriate read scope for the data you need.

Scope Not Recognized

Error: invalid_scope when requesting a token

Common causes:

  • Typo in scope name (e.g., read_published instead of read:published)
  • Requesting deprecated or non-existent scopes
  • Requesting scopes not available to your account tier

Solution: Verify scope names match exactly: read:published, read:draft, read:all-status, write, delete

Migrating from Simple Scopes

If you're upgrading from an earlier version that used simple read and write scopes:

Scope Migration

Old ScopeNew EquivalentNotes
readread:publishedAccess published content only
writewriteNo change
deletedeleteNo change

Update Your Code

// Old approach (deprecated)
const client = new TradingCardAPI({
scopes: ['read', 'write']
});

// New approach (recommended)
const client = new TradingCardAPI({
scopes: ['read:published', 'write'] // Be explicit about read level
});

Benefits of Granular Read Scopes

The new read:published, read:draft, and read:all-status scopes provide:

  • Better security - Request only the publication statuses you need
  • Clearer permissions - Explicit about what content you can access
  • Flexible access control - Different apps can have different visibility levels

Next Steps

Learn More

Try It Out

  1. Generate a Personal Access Token with specific scopes
  2. Make API requests and observe status-based filtering
  3. Try requesting data with different scope combinations
  4. Implement proper error handling for insufficient scope errors

Need Help?

  • Support - Get help with scope configuration
  • API Status - Check service status
  • Community - Connect with other developers

Summary

OAuth scopes provide fine-grained access control for the Trading Card API:

Five scopes - read:published, read:draft, read:all-status, write, delete

Status-based filtering - Automatic filtering based on read scope level

Principle of least privilege - Request only what you need

Flexible combinations - Mix scopes for your use case

Security - Separate tokens for different operations

Choose your scopes carefully, request the minimum permissions needed, and handle scope errors gracefully to build secure, reliable applications.