Skip to content

Latest commit

 

History

History
500 lines (357 loc) · 14.8 KB

File metadata and controls

500 lines (357 loc) · 14.8 KB

AGENTS.md

Project Overview

The Auth0 Node.js SDK v7 is a TypeScript-based Management-API-only SDK. Authentication has moved to @auth0/auth0-auth-js. The codebase uses Fern-generated code for the Management API with custom wrappers.

Key Capabilities:

  • Management API client for tenant administration and user management
  • Dual module system supporting both CommonJS and ESM
  • TypeScript-first with comprehensive type definitions
  • Legacy v4 compatibility layer for migration

Setup Commands

# Install dependencies
yarn install

# Build both CommonJS and ESM distributions
yarn build

# Build only CommonJS
yarn build:cjs

# Build only ESM (includes .mjs renaming)
yarn build:esm

# Run all tests
yarn test

# Run specific test suites
yarn test:unit      # Unit tests (src/management/tests)
yarn test:browser   # Browser environment tests
yarn test:wire      # Integration tests with mock server

# Run linter
yarn lint

# Fix linting issues
yarn lint:fix

# Generate documentation
yarn docs

# Validate entire project (lint, format, build, test)
yarn validate

Development Workflow

Local Development Commands

Common operations for working with the SDK:

# Build and test after changes
yarn build && yarn test

# Run tests with coverage
yarn test:coverage

# Watch mode for development (use specific TypeScript configs)
tsc --project ./tsconfig.cjs.json --watch

# Test specific functionality
yarn test:unit -- --testNamePattern="ManagementClient"

# Run linter with auto-fix
yarn lint:fix

# Format code
yarn format

Build Process

  • Source TypeScript files live in src/
  • Compiled output goes to dist/cjs/ (CommonJS) and dist/esm/ (ESM)
  • ESM build automatically renames .js → .mjs and .d.ts → .d.mts
  • Always run yarn build before testing SDK changes
  • Use TypeScript project references for different build targets

File Structure

src/                                    # TypeScript source
├── index.ts                           # Main SDK exports
├── utils.ts                           # Shared utilities
├── management/                        # Management API client
│   ├── Client.ts                      # Fern-generated client (READ-ONLY)
│   ├── api/                          # Fern-generated API definitions (READ-ONLY)
│   ├── wrapper/                      # Custom wrapper classes (SAFE TO EDIT)
│   │   └── ManagementClient.ts       # Main Management API wrapper
│   ├── request-options.ts            # Helper functions for API calls
│   └── tests/                        # Management API tests
├── lib/                              # Shared libraries and utilities
└── auth0/                            # Legacy compatibility exports

Code Style & Conventions

TypeScript Standards

  • Use strict TypeScript configuration (see tsconfig.base.json)
  • Define shared types in src/lib/models.ts
  • Follow existing patterns for API client implementations
  • Use proper async/await patterns, avoid callbacks
  • Import with .js extensions (TypeScript will resolve to .ts)

API Client Implementation Pattern

Every API client follows this structure:

class ApiClient {
    constructor(options: ClientOptions) {
        // Initialize with domain, credentials, etc.
    }

    async methodName(params: MethodParams): Promise<Response> {
        // Implementation with proper error handling
    }
}

Management API Wrapper Pattern

CRITICAL: Never edit Fern-generated files directly.

// ❌ Don't edit: src/management/Client.ts (Fern-generated)
// ✅ Use: src/management/wrapper/ManagementClient.ts

export class ManagementClient {
    private _client: FernClient;

    constructor(options: ManagementClientOptions) {
        this._client = new FernClient(options);
        // Custom logic, token handling, telemetry
    }
}

Request Options Pattern

Use helper functions from src/management/request-options.ts:

import { withTimeout, withRetries, withHeaders, CustomDomainHeader } from "auth0";

const options = {
    ...withTimeout(30),
    ...withRetries(3),
    ...CustomDomainHeader("auth.example.com"),
};

Error Handling

  • ManagementError - For Management API errors (the only error class in v7)
  • Use .withRawResponse() for accessing raw HTTP response data
  • Provide clear, actionable error messages

Testing Instructions

Running Tests

# All tests
yarn test

# Specific test projects
yarn test:unit      # Fast unit tests
yarn test:browser   # Browser compatibility tests
yarn test:wire      # Integration tests with mock server

# With coverage
yarn test:coverage
yarn test:coverage:unit

# Specific test files
yarn test -- src/management/tests/ManagementClient.test.ts

# Pattern matching
yarn test -- --testNamePattern="should authenticate user"

Test Structure

  • Tests mirror src/ directory structure in corresponding tests/ folders
  • Use .test.ts extensions
  • Unit tests use mocks/stubs for external dependencies
  • Integration tests use MSW (Mock Service Worker) for HTTP mocking
  • Browser tests validate cross-platform compatibility

Writing Management API Tests

Pattern for testing Management API wrappers:

import { ManagementClient } from "../wrapper/ManagementClient.js";

describe("ManagementClient", () => {
    let client: ManagementClient;

    beforeEach(() => {
        client = new ManagementClient({
            domain: "test.auth0.com",
            clientId: "test-client-id",
            clientSecret: "test-client-secret",
        });
    });

    it("should handle API calls correctly", async () => {
        // Test implementation
    });
});

Writing Management API Integration Tests

Pattern for testing Management API clients with HTTP mocking:

import { ManagementClient } from "../src/index.js";

describe("ManagementClient", () => {
    let management: ManagementClient;

    beforeEach(() => {
        management = new ManagementClient({
            domain: "test.auth0.com",
            clientId: "test-client-id",
            clientSecret: "test-secret",
        });
    });

    it("should call Management API correctly", async () => {
        // Test implementation
    });
});

Test Coverage Requirements

  • Maintain minimum coverage thresholds (see jest.config.mjs)
  • Add tests for any new API methods or features
  • Test both success and error paths
  • Test edge cases and validation logic

Common Development Tasks

Adding New Management API Methods

  1. Add method to appropriate class in src/management/wrapper/
  2. Follow existing patterns for parameter validation
  3. Add proper TypeScript types
  4. Write comprehensive tests
  5. Update API reference documentation

Extending Management API Wrapper

  1. Never edit src/management/Client.ts or src/management/api/ (Fern-generated)
  2. Extend src/management/wrapper/ManagementClient.ts
  3. Add custom methods with proper error handling
  4. Use helper functions from request-options.ts
  5. Add tests to src/management/tests/

Working with Legacy Compatibility

  • Legacy exports in legacy/exports/ maintain v4 API compatibility
  • Use import { ... } from 'auth0/legacy' for v4 imports
  • See v5_MIGRATION_GUIDE.md for breaking changes
  • Test both new and legacy APIs when making changes

Module System Development

The SDK supports dual module systems:

// CommonJS (default)
const { ManagementClient } = require("auth0");

// ESM
import { ManagementClient } from "auth0";

// Legacy v4 compatibility
import { ManagementClient } from "auth0/legacy";

Pull Request Guidelines

Before Committing

# Always run validation before commit
yarn validate

This runs: lint → format → build → test → package validation

PR Checklist

  • All tests pass locally (yarn test)
  • Code builds successfully (yarn build)
  • Linting passes (yarn lint)
  • Code is formatted (yarn format)
  • New code has corresponding tests
  • TypeScript compiles without errors
  • Updated API reference if adding public methods
  • Added entry to CHANGELOG.md if user-facing change
  • Tested with both CommonJS and ESM if applicable
  • Verified backward compatibility

Commit Message Format

Follow conventional commits style:

  • feat: add support for new Management API endpoint
  • fix: resolve token refresh issue in Authentication client
  • docs: update Management API examples
  • test: add coverage for passwordless authentication
  • refactor: simplify error handling in base client

Security Considerations

API Credentials

  • Never commit Auth0 credentials, client secrets, or tokens
  • Use environment variables for sensitive configuration
  • Example configs use placeholder values
  • Test configurations should use dedicated development tenants

Validation & Safety

  • All inputs validated before API calls
  • Proper sanitization of user-provided data
  • JWT validation follows security best practices
  • Rate limiting and retry logic implemented

Testing with Real Auth0 Tenants

  • Use dedicated development/testing tenants only
  • Never run tests against production tenants
  • Store credentials in environment variables
  • Clean up test resources after test runs

Debugging Tips

Enable Debug Logging

# Set environment variable for verbose logging
export DEBUG=auth0:*
yarn test

Common Issues

  • Build errors: Check TypeScript configuration and import paths
  • Fern generation conflicts: Never edit auto-generated files
  • Module resolution: Ensure .js extensions in imports
  • Test failures: Check mock server setup in wire tests
  • Type errors: Verify all imports resolve correctly

Useful Commands

# Check compiled output structure
ls -la dist/cjs/ dist/esm/

# Validate package exports
yarn lint:package

# Run specific test suite with verbose output
yarn test:unit --verbose

# Check TypeScript compilation
tsc --noEmit --project ./tsconfig.base.json

# Analyze bundle size
du -sh dist/

Architecture Notes

Request Flow

  1. SDK Entry (src/index.ts) → Export all public APIs
  2. Client Initialization → Authentication or Management client
  3. Method Call → Route to appropriate API handler
  4. Request Processing → Add authentication, headers, retries
  5. HTTP Client → Make actual API call to Auth0
  6. Response Processing → Parse response, handle errors
  7. Return Result → Typed response to consumer

Fern Integration

  • Management API uses Fern-generated code for type safety
  • Generated files are read-only - never edit directly
  • Custom logic goes in wrapper classes
  • Fern handles OpenAPI spec changes automatically

Module Architecture

auth0 (main export)
├── ManagementClient (tenant administration)
└── Legacy exports (v4 compatibility)

Additional Resources

  • Migration Guide: v5_MIGRATION_GUIDE.md
  • API Reference: reference.md
  • Full Documentation: auth0.com/docs
  • TypeScript Docs: Generated in docs/ directory
  • Examples: See README.md for usage examples

Quick Reference

Key Configuration Options

// Management Client
const management = new ManagementClient({
    domain: "your-tenant.auth0.com",
    clientId: "your-client-id",
    clientSecret: "your-client-secret",
    scope: "read:users create:users", // Optional
});

Key Files to Know

  • src/index.ts - Main SDK exports
  • src/management/wrapper/ManagementClient.ts - Management API wrapper
  • src/management/request-options.ts - Request configuration helpers
  • src/lib/models.ts - Shared TypeScript types
  • jest.config.mjs - Test configuration with multiple projects
  • Files marked "auto-generated by Fern" - READ-ONLY

Environment Variables for Testing

AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=your-test-client-id
AUTH0_CLIENT_SECRET=your-test-client-secret
AUTH0_M2M_TOKEN=your-machine-to-machine-token

Beta Track Releases

Applies only when working on the beta branch.

This SDK ships two tracks from one npm package (auth0):

  • Stable (master): EA/GA endpoints only. Released by a maintainer via a release/* branch.
  • Beta (beta): a superset of stable plus beta-only endpoints. Released automatically when a PR is merged into beta.

The beta branch is regenerated from the stable spec plus the beta-only spec files; it is never produced by merging master into beta. It receives one combined regeneration PR (stable + beta) as a single squash commit. The beta-only versus stable-mirrored split cannot be detected from code or file paths, so it must be recorded in the squash commit message.

Versioning

Beta = the next stable minor + -beta.N, derived from git tags. Latest stable v6.3.0 → beta v6.4.0-beta.N; -beta.N auto-increments; once stable v6.4.0 ships, beta rolls to v6.5.0-beta.1. No state file.

When merging a beta regeneration PR

Squash and merge with a commit message that marks each group:

Regenerate SDK (stable + beta) (#<pr-number>)

<!-- BETA -->
- feat: add `Management.Sandbox` preview API (Beta)
<!-- /BETA -->

<!-- STABLE -->
- feat: add tenant security headers configuration
<!-- /STABLE -->
  • Beta-only changes go inside the BETA markers; stable-mirrored changes go inside the STABLE markers.
  • The <!-- ... --> markers are HTML comments and stay invisible in GitHub's rendered view.
  • Omitting a section renders a "No ... changes in this release." note; omitting both falls back to the raw commit subject. Always prefer the structured form.
  • Everything reaches beta through a PR. Never push directly to beta (a direct push will not trigger a release).

Do not hand-edit release files on beta

The Beta Auto-Release workflow (.github/workflows/npm-release-beta.yml) owns versioning. When a PR is merged into beta it computes the next vX.Y.0-beta.N, aborts if that tag already exists, stamps .version, package.json, src/management/version.ts, and CHANGELOG.md, creates the release commit through the GitHub API (so it is signed/Verified, no GPG key), publishes to npm with --tag beta, tags it, and publishes a GitHub prerelease. Never manually bump these files on beta.

Hand-written code

Code outside of the Fern-generated directories is hand-written and is not regenerated on beta. A fix on master does not reach beta automatically, so hand-written changes must be PR'd to both master and beta.

Important notes for agents on the beta branch

  • Never hand-edit .version, package.json (version field), src/management/version.ts, or CHANGELOG.md; mark beta vs. stable changes in the squash commit message instead (see above).
  • Do not merge master into beta; the branch is always regenerated from scratch.