Skip to main content

Security Best Practices

This guide covers authentication, API key management, data handling, and compliance requirements for integrating with the relay platform.

Authentication Model

relay uses two authentication mechanisms depending on your integration path:

IntegrationAuth MethodHeaderToken Lifetime
REST API (direct)API KeyX-API-KEYPermanent (until rotated)
Embedded SDKPublishable Key + JWTAuthorization: Bearer <token>1 hour

API Key Authentication (REST API)

All direct API calls require your API key in the X-API-KEY header:

curl -X GET "https://api.ir.app/api/experian/renters/{renterId}/report" \
-H "X-API-KEY: your-api-key"

Your API key is a secret credential — treat it like a database password.

danger

Never expose your API key in client-side code, public repositories, or browser network requests. API keys grant full access to your account's data.

SDK Token Exchange (Embedded SDK)

The SDK uses a two-step authentication flow that keeps secrets server-side:

  1. Your page loads the SDK with a publishable key (safe for client-side use)
  2. The SDK exchanges the publishable key for a short-lived JWT token via POST /auth/token/exchange
  3. All subsequent SDK requests use the JWT in the Authorization header
  4. The JWT is origin-bound — it can only be used from the domain that requested it
Browser                        relay
│ │
│ SDK loads with pk_live_* │
│─────────────────────────────>│
│ POST /auth/token/exchange │
│ (publishableKey + Origin) │
│─────────────────────────────>│
│ JWT (1hr, origin-bound) │
│<─────────────────────────────│
│ All API calls use Bearer │
│─────────────────────────────>│

The SDK handles token refresh automatically. You do not need to manage tokens yourself.

POST /auth/token/exchange requires the X-Publishable-Key and Origin headers and returns:

{
"token": "<JWT>",
"token_type": "Bearer",
"expires_in": 3600,
"flags": { "someFeatureFlag": true }
}

flags is a set of server-evaluated feature flags for the account/key, delivered alongside the token so the embedded view can branch on account-level feature state without a separate round trip. Treat it as opaque, additive, and non-exhaustive — new flags may appear without notice and unrecognized keys should be ignored.

API Key Management

Key Types

Key PrefixEnvironmentUsage
pk_live_*ProductionPublishable key — safe for client-side SDK
pk_test_*Test/StagingPublishable key — safe for client-side SDK
API Key (no prefix)BothServer-side only — never expose to clients

Storage Guidelines

Do:

  • Store API keys in environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.)
  • Use different keys for each environment (development, staging, production)
  • Restrict key access to the services that need them

Don't:

  • Commit keys to version control (add to .gitignore / .env)
  • Log API keys in application logs
  • Pass keys as URL query parameters
  • Share keys over unencrypted channels (email, Slack messages)
# Good: environment variable
export RELAY_API_KEY="your-api-key"

# Good: .env file (add .env to .gitignore)
RELAY_API_KEY=your-api-key

Key Rotation

If you suspect a key has been compromised:

  1. Contact relay support immediately to issue a new key
  2. Update all services that use the compromised key
  3. Verify the old key is no longer accepted
  4. Audit recent API activity for unauthorized access

Iframe Trust Model (SDK)

The Embedded SDK renders inside an iframe served from relay's domain. This architecture provides important security boundaries:

How It Works

  • The SDK creates an iframe pointed at https://embedded.ir.app (environment-specific variants: embedded.stage.ir.app, embedded.preprod.ir.app)
  • Your page and the iframe communicate via the browser's postMessage API
  • The iframe validates the origin of every incoming message
  • Sensitive data (SSN, credit reports) never touches your DOM

Origin Validation

The JWT issued during token exchange is bound to the Origin header of the requesting page. This means:

  • A token obtained on https://yourapp.com cannot be reused on https://attacker.com
  • The iframe validates that messages come from the expected parent origin
  • CSRF attacks are mitigated because the token won't work cross-origin

What This Means for You

  • You never handle raw PII — the iframe collects and submits sensitive data directly to relay
  • Your page receives only results — application IDs, statuses, and scores (not SSNs or full reports)
  • No PCI/PII compliance burden for SDK integrations — sensitive data stays within relay's domain
tip

If your integration uses the REST API instead of the SDK, you are responsible for PII handling and should follow the Data Handling section below.

Handling Personally Identifiable Information (PII)

REST API integrations handle sensitive consumer data. Follow these practices to stay compliant.

Data Classification

ClassificationExamplesHandling
Highly SensitiveSSN, credit report data, KBA answersEncrypt at rest, never log, minimize retention
SensitiveName, DOB, address, phone, emailEncrypt at rest, mask in logs
Non-SensitiveScreening IDs, status codes, timestampsStandard handling

Transmission Security

  • All relay APIs require HTTPS (TLS 1.2+). HTTP requests are rejected.
  • Validate TLS certificates in your HTTP client — do not disable certificate verification.
  • Use the latest version of your HTTP client library to ensure current cipher suites.

Logging and Monitoring

// BAD: logging raw PII
console.log(`Registering renter: SSN=${ssn}, DOB=${dob}`);

// GOOD: log only identifiers
console.log(`Registering renter: id=${renterId}`);
  • Never log SSNs, full credit report data, or KBA answers
  • Mask or redact sensitive fields before logging (e.g., ***-**-7315)
  • relay's API scrubs sensitive data from internal logs automatically

Data Retention

  • Credit reports expire 30 days after generation
  • Do not cache or store credit report data beyond what is necessary for your business purpose
  • If you must store report data, encrypt it at rest and enforce access controls
  • Delete consumer data when the business purpose has been fulfilled

Brute Force Protection

The API enforces rate limiting and Experian-driven lockouts on authentication-related endpoints:

ProtectionBehavior
Failed KBA/OTP attemptsRepeated failures cause Experian to block the user. The block duration is set by Experian — the error message includes the unblock time.
API rate limiting (SDK token exchange)60 requests per minute per publishable key (fixed one-minute window; per-key overrides available). Exceeding it returns HTTP 429 with a Retry-After header.

When a consumer is locked out:

  • The REST API returns HTTP 423 Locked (errorCode 300) with the unblock time in the message
  • The SDK/platform path returns SCREENING_TOO_MANY_ATTEMPTS (HTTP 429)
  • The block expires automatically at the time indicated; contact support if you need help sooner
warning

Do not retry failed KBA or OTP submissions automatically. Each failed attempt counts toward the lockout threshold. Present errors to the user and let them correct their input.

FCRA Compliance (FR-9)

relay's credit reporting services are governed by the Fair Credit Reporting Act (FCRA). As an integrator, you must:

Permissible Purpose

  • Only pull credit reports for a legally permissible purpose (e.g., tenant screening for a rental application)
  • Document and retain evidence of the consumer's consent
  • The SDK handles consent collection automatically; REST API integrators must collect consent independently

Consumer Disclosures

  • Inform consumers that a credit report will be pulled before initiating the screening
  • Provide consumers with a copy of their rights under the FCRA
  • If an adverse action is taken based on report data, provide the required adverse action notice

Data Access Controls

  • Restrict access to credit report data to authorized personnel only
  • Maintain audit logs of who accessed report data and when
  • The API enforces row-level security — each API key can only access its own account's data

Report Sharing

When sharing reports between consumers and organizations/agents:

Embedded SDK / platform path — sharing is consumer-consent driven. The embedded flow calls these endpoints and surfaces the results via the onReportShared / onReportRevoked SDK callbacks:

# Consumer consents to share their report
POST /reports/{screeningId}/consent-to-share

# Consumer revokes sharing (permanent — cannot be re-enabled for the same share)
POST /reports/{screeningId}/revoke-sharing

REST API path — partners link and unlink renters directly:

# Link a renter's report to an organization
PUT /api/experian/renters/{renterId}/organizations/{organizationId}

# Unlink (revoke access)
DELETE /api/experian/organizations/{organizationId}/renters/{renterId}
  • Consumers control who can view their reports
  • Revocation takes effect immediately; on the SDK path it is permanent

Compliance Checklist

Use this checklist to verify your integration meets security and compliance requirements:

API Key Security

  • API keys stored in environment variables or secrets manager
  • Keys are not committed to version control
  • Different keys used for test and production environments
  • Keys are not exposed in client-side code or logs

Data Handling

  • All API calls use HTTPS
  • SSNs and sensitive data are not logged
  • Credit report data retention policy is defined and enforced
  • PII is encrypted at rest if stored

Authentication

  • Failed KBA/OTP attempts are not auto-retried
  • HTTP 423 (Locked) responses are handled gracefully
  • SDK publishable keys are used for client-side (not API keys)

FCRA Compliance

  • Consumer consent is collected before screening
  • Adverse action notice process is documented
  • Access to report data is restricted and audited
  • Report sharing respects consumer revocation

SDK-Specific

  • SDK loads over HTTPS
  • onError callback handles authentication failures gracefully
  • SDK is destroyed on user logout (sdk.destroy())
  • No attempts to access iframe contents directly

Next Steps