Plaid logo
Core Exchange
ALL DOCS

Authentication

  • Overview
  • Planning your integration
  • OAuth server setup
  • Implementing the OAuth flow
  • App2App
Open nav
Core Exchange
Plaid.comGet Started

OAuth server setup

How to configure your OAuth 2.0/OIDC server for Plaid Core Exchange

Quick reference

ComponentRequirementWhere to find details
Discovery endpoint/.well-known/openid-configurationConfiguration requirements
JWKS endpointPublic HTTPS endpointJWKS section
Consistency key7+ character unique IDUnique user identifier
CredentialsClient ID + SecretCredentials section
Required scopesopenid, offline_accessWell-known configuration

OAuth server setup

Your OAuth 2.0 server needs to issue standards-compliant tokens. Plaid strongly recommends implementing OpenID Connect with the OIDC Discovery Specification. OIDC enables a better user experience for returning users, centralized consent management, and optimal API performance through the ID token's sub field. Plain OAuth 2.0 is supported but requires providing the unique user identifier via the /customers/current endpoint instead.

Implementation options

Use an existing identity provider - Okta, Auth0, Ping Identity, Azure AD, or AWS Cognito all work, and provide the fastest implementation path.

Plaid recommends Okta's Plaid integration.

Build your own - Use an OIDC-certified library. This option gives you more control but takes more time.

Don't roll your own OAuth implementation from scratch. Custom, non-standard implementations create headaches for everyone. Stick to certified tools and established identity providers.

Configuration requirements

ConfigurationNotes
Server domainPick a domain for your OAuth server, usually something like auth.yourbank.com or yourbank.okta.com. Keep it separate from your API server. HTTPS is required.
Discovery endpointPlaid pulls your server config from /.well-known/openid-configuration. If your domain is https://auth.firstplatypusbank.com, Plaid will hit https://auth.firstplatypusbank.com/.well-known/openid-configuration. Make sure it returns the details in the next section.

Well-known configuration

Your /.well-known/openid-configuration endpoint is public (no auth required). When Plaid hits it, the response should include at minimum these values:

PropertyDescriptionRequiredType
authorization_endpointWhere users authenticate. This endpoint hosts your login page. Must support TLS and be publicly accessible.YesURL
token_endpointWhere Plaid exchanges authorization codes for access tokens. Backend-to-backend only.YesURL
userinfo_endpointWhere Plaid retrieves the user identifier. Required for OIDC. Plain OAuth 2.0 implementations that do not use OIDC must instead provide the identifier via /customers/current.Yes (OIDC)URL
token_endpoint_auth_methods_supportedHow Plaid authenticates when requesting tokens. If omitted, Plaid defaults to basic authentication.NoArray of strings
response_types_supportedSupported response types. Must include code.YesArray of strings
scopes_supportedFor OIDC implementations, must include openid and offline_access at a minimum. Plain OAuth 2.0 only requires offline_access. See details below.YesArray of strings

Scope details:

  • openid - Enables OIDC features. Lets Plaid read the user identifier from the ID token, enabling returning user experience, optimized API traffic, and centralized consent management. (If this scope is unavailable, Plaid will query /customers/current instead, but OIDC-specific features won't be available.)
  • offline_access - Gives Plaid a refresh token to fetch data in the background. Required for use cases that need data access beyond the initial OAuth session, such as balance checks for stored bank accounts (recurring transfers, saved payment methods), transaction subscriptions, and ongoing data updates.

Example

Plaid's request
curl -X GET 'https://auth.firstplatypusbank.com/.well-known/openid-configuration'
Your response
{
  "authorization_endpoint": "https://auth.firstplatypusbank.com/oauth2/v1/authorize",
  "token_endpoint": "https://auth.firstplatypusbank.com/oauth2/v1/token",
  "userinfo_endpoint": "https://auth.firstplatypusbank.com/oauth2/v1/userinfo",
  "token_endpoint_auth_methods_supported": ["client_secret_basic"],
  "response_types_supported": ["code"],
  "scopes_supported": ["openid", "offline_access"]
}

What to validate

When Plaid (or your own tooling) fetches your well-known configuration, confirm:

  • All endpoint URLs use HTTPS, resolve via DNS, and are reachable from the public internet with valid Production TLS certificates.
  • The endpoint returns HTTP 200 with Content-Type: application/json and well-formed JSON.
  • Required properties in the table above are present and correctly populated (including authorization_endpoint, token_endpoint, response_types_supported with code, and scopes_supported with offline_access and, for OIDC, openid).
  • For OIDC, jwks_uri is present, publicly accessible, and returns at least one signing key in a valid JWKS document.

Note for multi-institution deployments: If you serve multiple financial institutions, the sub field in the ID token must be unique per institution (but doesn't need to be unique across all institutions).

Unique user identifier (consistency key)

Plaid needs a stable identifier for each user, something that never changes, is unique across your user base, and stays consistent when that user connects multiple apps. This identifier (often called the "consistency key") enables Plaid to:

  • Show users all their active connections in one place (my.plaid.com)
  • Maintain a user-level view in Permissions Manager
  • Optimize API traffic by recognizing returning users
  • Enable the returning user experience

Requirements

The identifier must be:

  • Stable - Never changes for the duration of the user's relationship with you
  • Unique - No two users share the same identifier
  • Consistent - Same value across all apps a user connects to via Plaid
  • Non-sensitive - Should not expose personally identifiable information (avoid SSN, email, phone)
  • Sufficient length - Minimum seven characters

In practice, the best option is usually an internal customer identifier from your core system (for example, a GUID or numeric customer ID) as long as it is never reused, never changes, and does not expose login names or account numbers. Avoid using online banking usernames, email addresses, phone numbers, or account numbers as the identifier.

How to provide it

You have three options. Use the first available method:

  1. sub field in the ID token (recommended) - Include the user identifier as the sub claim when issuing the id_token during token exchange. Plaid reads this automatically.

  2. userinfo endpoint - Return the identifier in the response from your userinfo_endpoint. Plaid will query this endpoint if the sub field isn't available.

  3. /customers/current endpoint - Return the identifier in the Core Exchange /customers/current response. Plaid requires this endpoint for plain OAuth 2.0 implementations that don't use OIDC.

Most integrations use option 1. Including the sub field in the ID token is the standard OIDC approach and requires no additional endpoint calls.

Example

When Plaid requests a token, your /token endpoint responds with an id_token that includes:

Token response example
{
  "access_token": "agstynmdygjdghabrgraeh...",
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "dhcsrtjsrgayvkdisfdgntshstu..."
}
Decoded ID token payload example
{
  "sub": "user_12345678",
  "iss": "https://auth.firstplatypusbank.com",
  "aud": "dc1fe34ae9e5e98147f2fd76060016a4",
  "exp": 1672444800,
  "iat": 1672441200
}

The sub value (user_12345678) is the consistency key. It's 13 characters, unique to this user, and will never change.

JWKS (JSON Web Key Set)

Only OIDC implementations that issue ID tokens need to expose a JWKS endpoint. Plain OAuth 2.0 implementations don't need to provide one.

JWKS is how Plaid verifies your tokens are valid. The jwks_uri points to your public keys. Plaid uses them to verify the digital signatures on JWTs, such as the id_token. Plaid automatically fetches and caches your JWKS.

Example JWKS response
{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "kid": "ABCD1234",
      "n": "4MZuI7r3F5y...",
      "e": "AQAB",
      "alg": "RS256"
    }
  ]
}

Keep your JWKS healthy:

  • Host it over HTTPS (non-negotiable).
  • Rotate signing keys at least annually, or immediately if compromised.
  • Include a kid (Key ID) in every key for quick lookup.
  • Use strong algorithms: RSA-2048 or better (RS256, ES256, etc.).

Key rotation process

Rotating JWKS keys without breaking Plaid's token verification:

  1. Publish the new key - Add your new key to the JWKS with a unique kid. Keep the old key in the response.

  2. Wait for cache refresh - Plaid caches JWKS for 24 hours to reduce load on your endpoint. Wait at least 24 hours (preferably 48 hours) before proceeding to ensure Plaid has fetched and cached the new keys.

  3. Start signing with new key - Update your ID tokens to use the new kid in the JWT header. Plaid will use the cached JWKS to verify tokens signed with either the old or new key.

  4. Monitor for errors - Watch for signature validation errors (invalid_signature, kid_not_found) in your logs and Plaid's error reports. If everything's clean for 48+ hours, proceed.

  5. Remove the old key - After confirming no errors for at least 48 hours, remove the old key from your JWKS. Plaid will remove the old key from its cache the next time it fetches your JWKS (within 24 hours).

JWKS caching behavior:

  • Cache duration: 24 hours
  • Fetch trigger: Cache miss or expiration
  • During rotation: Both old and new keys remain cached and valid during the transition period

Emergency rotation: If a key is compromised, rotate immediately. Coordinate with your Plaid contact to minimize disruption. Be prepared for some token validation failures during emergency rotations.

Recommended schedule: Annually at a minimum. Schedule rotations during low-traffic periods when possible.

Credentials

Plaid needs credentials to authenticate when requesting access tokens. You'll issue us a client ID (public identifier) and client secret (password).

Client ID

The client ID is public, but don't make it easy to guess. Length: 8-256 characters.

How to create one

Generate a random string using your language's cryptographically secure random number generator (CSPRNG), then encode as hexadecimal. Target 16 random bytes, which produces a 32-character hex string.

Generate a random client ID
import crypto from "crypto";
const randomString = crypto.randomBytes(16).toString("hex");
console.log(randomString)

Client secret

The client secret is Plaid's password. Treat it like one. Follow these security best practices:

  • Generate it securely - Use a CSPRNG (cryptographically secure pseudo random number generator). Don't use UUIDs, as many libraries leak timestamps or MAC addresses.
  • Never store it in plain text - Encrypt or hash it. Always.
  • Make it visually distinct - Different format from the client ID helps prevent copy/paste errors.

Length: 8-256 characters.

How to generate one

Generate a 256-bit value using your language's CSPRNG, then encode as hexadecimal. This produces a 64-character hex string.

Generate a random client secret
import crypto from "crypto";
const randomString = crypto.randomBytes(32).toString("hex");
console.log(randomString)

Token expiration

Configure your token lifetimes to balance security with usability.

Access tokens: 15 minutes

Short-lived access tokens limit exposure if a token is compromised. Plaid checks expiration before each API call and automatically refreshes when needed.

Refresh tokens: 13+ months

Compliance requires users to reauthorize every 12 months, which Plaid handles automatically. Rotating refresh tokens or setting their expiration to 13+ months ensures they remain valid through this cycle. The extra buffer (13+ months is common) accounts for high-traffic periods like tax season, when users may not reauthorize immediately.

Setup checklist

  • OAuth server configured with OIDC support
  • Discovery endpoint returns valid configuration
  • JWKS endpoint publicly accessible with valid keys
  • Client ID and secret generated securely
  • Consistency key implemented (via sub, userinfo, or /customers/current)
  • TLS certificates valid (not self-signed for Production)
  • Token expiration configured (15 min for access, 13+ months for refresh)
  • All endpoints are tested and responding correctly