Authentication
Building Plaid Core Exchange OpenID Connect Protocol
Overview
Core Exchange uses the OpenID Connect protocol (OIDC) to authenticate your customers. OIDC is an extension of OAuth2. Plaid will use the OIDC flow to get authorization from the end user. This authorization allows Plaid to access your Core Exchange API on their behalf. In order to successfully allow your users to complete the authorization flow, you must:
- Create an OIDC-compliant server
- Issue Plaid a client ID and client secret
- Guide your users through all the steps in the authorization flow
Create an OIDC-compliant server
You can generate an OIDC-compliant server in any of the following ways:
- Using your existing OAuth identity provider. (For example, Okta, Auth0, Ping Identity, Azure Active Directory, AWS Cognito)
- If you don't yet have an identity provider, Plaid recommends our partner, Okta. Okta is an industry-leading, independent provider with expertise onboarding data partners to OAuth integrations. Contact us for help getting started with Okta.
- Building a server with an OIDC-certified open source or commercial implementation
- Building a server from scratch (not recommended)
Basic server requirements
Configuration | Notes |
---|---|
Server domain |
|
Well-known configuration endpoint |
|
Well-known configuration
The /.well-known/openid-configuration
endpoint of the OIDC server is a public endpoint that accepts HTTP GET requests without authentication.
It returns a JSON object containing the minimum following values:
Property | Description |
---|---|
authorization_endpoint | The endpoint hosting the user authentication page. |
token_endpoint | The endpoint Plaid will call to exchange the authorization code for an access token. |
userinfo_endpoint | The endpoint Plaid will call to retrieve the user identifier. |
token_endpoint_auth_methods_supported | The supported authentication methods Plaid can use to request an access token from the token_endpoint .(If omitted, Plaid will use basic authentication by default.) |
response_types_supported | An array of supported response types. Plaid expects this to include code . |
scopes_supported | An array that must include at minimum openid and offline_access :
|
Example
Plaid's request:
1curl GET 'https://auth.firstplatypusbank.com/.well-known/openid-configuration'
Your response:
1{2 "authorization_endpoint": "https://auth.firstplatypusbank.com/oauth2/v1/authorize",3 "token_endpoint": "https://auth.firstplatypusbank.com/oauth2/v1/token",4 "userinfo_endpoint": "https://auth.firstplatypusbank.com/oauth2/v1/userinfo",5 "token_endpoint_auth_methods_supported": ["client_secret_basic"],6 "response_types_supported": ["code"],7 "scopes_supported": ["openid", "offline_access"]8}
Issue Plaid a client ID and client secret
In order to allow Plaid to authenticate its request for an access token, you must issue Plaid a client ID and client secret. These allow Plaid to identify itself. You may create the client ID and client secret using your preferred method, but we provide some guidance in the sections below.
Client ID
A client ID is a public identifier that you assign to Plaid. While it is not secret, we recommend choosing a client ID that is not easy to guess.
Note: The client ID must be between 8 and 256 characters long.
How to create a client ID
One way to create a client ID is to use a random 32-character hex string. Example:
1import crypto from "crypto";2const randomString = crypto.randomBytes(16).toString("hex");3console.log(randomString)
Client secret
The client secret is essentially a password that you assign to Plaid. In order to keep it secure, please follow these best practices:
- Generate the client secret in a way that makes it impossible to guess or backwards-generate. (For example, do not use a UUID as many common libraries take into account the timestamp or MAC address of the generating server.)
- Never store the client secret in plain text—always keep it encrypted or hashed.
- Make the client secret visually different from the client ID. (This reduces the risk of a user copy/paste error when handling the client ID and client secret.)
Note: The client secret must be between 8 and 256 characters long.
How to generate a client secret
One way to securely generate a client secret is to follow the steps below:
- Create a 256-bit value using a cryptographically secure pseudo random number generator (CSPRNG)
- Convert the value from step 1 to a hexadecimal representation
Example:
1import crypto from "crypto";2const randomString = crypto.randomBytes(32).toString("hex");3console.log(randomString)
Authorization flow
Once you have an OIDC-compliant server and have issued Plaid a client ID and client secret, the authorization flow occurs as follows:
- Plaid redirects the end user to your
authorization_endpoint
- The user completes all authentication steps and you generate an authorization code
- Plaid uses the authorization code to request an access token
- Plaid uses the access token to:
- Identify the user
- Authenticate Plaid's requests to your Core Exchange API
(This flow conforms to commonly implemented patterns for the OIDC spec. Plaid welcomes partner feedback.)
1. Plaid redirects the end user
When your user first initiates the process of linking their account, Plaid redirects their browser to the authorization_endpoint
specified in your well-known configuration.
Plaid's redirect includes the following query parameters:
Query parameter | Value | Description |
---|---|---|
response_type | code | The type of response Plaid expects. |
redirect_uri | https://cdn.plaid.com/link/v2/stable/oauth.html | Where Plaid expects your organization to redirect back to once the user completed all authentication steps. |
scope | At a minimum openid and offline_access | The set of scopes Plaid requests access to. |
client_id | A client ID | The client ID you issued to Plaid. |
state | An opaque string | Your organization will return the same string when redirecting to the redirect_uri . |
prompt | May be any combination of the following:
| Specifies the type of authentication prompt the server will send to the end user. |
code_challenge | The code_verifier , either as a Base64URL-encoded hash or in plain text | Optional: This value will be included only if your organization is using PKCE. |
code_challenge_method | Indicates the format of the code_challenge . May be any either:
| Optional: This value will be included only if your organization is using PKCE. |
Example
Plaid's redirect:
1https://auth.firstplatypus.com/oauth2/v1/authorize?response_type=code&client_id=dc1fe34ae9e5e98147f2fd76060016a4&redirect_uri=https%3A%2F%2Fcdn.plaid.com%2Flink%2Fv2%2Fstable%2Foauth.html&state=v2.9f77edf0-a328-4501-9528-4a5f460cf770.0.0&scope=openid%20offline_access%20accounts%20transactions&prompt=login&code_challenge=4dKRcTlKg7PbBxYokEH5gbfwfXcUdvDVYVdFZniVq4s&code_challenge_method=S256
This page will be requested directly by the user's device. Your authorization endpoint must support TLS and be publicly accessible. Control of user authentication has now been handed off to you. A typical authentication flow will include a username and password submission form and a 2FA step. For partners with native mobile applications, Plaid strongly recommends enabling support for App2App and using biometric authentication to improve the user's authentication experience.
2. You give Plaid an authorization code
After the user completes all required authentication steps, your organization generates a temporary authorization code and redirects the user's browser back to the redirect_uri
. The following query parameters must be included with the request:
Query parameter | Description |
---|---|
code | The temporary authorization code. Plaid exchanges this for an access token in the next step. |
state | The state parameter from the previous step. Plaid verifies that the two values match. |
Example
Your response:
1https://cdn.plaid.com/link/v2/stable/oauth.html?code=1284918391&state=eyJvYXV0aF9zdGF0ZV
Note: If a user does not complete all the required steps (for example, if they choose to cancel rather than authorize) you should handle it as an error. See the user cancellation section for more information.
3. Plaid requests an access token
Plaid sends a request to your token_endpoint
.
Unlike the two previous steps, the request to the token_endpoint
is a backend-to-backend call and must be authenticated.
The authentication credentials consist of the client ID and client secret you issued to Plaid.
The authentication method will be one of the authentication methods specified in your well-known configuration.
For example, if the authentication method is set to client_secret_basic
, Plaid will include a basic authentication header in its request.
Plaid will send the parameters listed in the table below in the body of the request, in application/x-www-form-urlencoded
format.
Body parameters
Body parameter | Value | Description |
---|---|---|
prompt | consent | Specifies the type of a prompt the server will send to the end user. |
grant_type | authorization_code | The type of grant Plaid is exchanging for an access token. (In this case, an authorization code.) |
code | The code you sent to Plaid in the previous step | The temporary authorization code Plaid is exchanging for the access token. |
redirect_uri | https://cdn.plaid.com/link/v2/stable/oauth.html | Where Plaid expects your organization to redirect back to once the user completed all authentication steps. |
scope | An array of scopes, for example: [offline_access, openid, accounts, transactions, identity] | The set of possible scopes. |
audience | A string, for example: https://test-api | Optional: Defines who the token is for. This value will be sent if Plaid has this information. More information |
code_verifier | The code_verifier , created prior to starting the authentication flow | Optional: This value will be included only if your organization is using PKCE. |
Example
Plaid's request (using basic authentication):
1curl --request POST 'https://auth.firstplatypusbank.com/oauth2/v1/token' \2--header 'Content-Type: application/x-www-form-urlencoded' \3--header "Authorization: Basic YzVhNTI0NWIwNjJiZjg0MjBkMTFhYjQzNjFiMjhhMTU6clZYWU9vUVM0ckhVRzc5bl80OGFs"4--data-raw '{5 "grant_type": "authorization_code",6 "code": "1284918391",7 "redirect_url": "https://cdn.plaid.com/link/v2/stable/oauth.html"8}'
Response parameters
Your organization validates that the client_id
, client_secret
, code
and redirect_uri
all match the expected values.
Your response must contain access_token
, id_token
, and refresh_token
, all of which Plaid needs to later access your Core Exchange API:
Property | Description |
---|---|
access_token | An opaque string (likely a JWT structured according to the Oauth2 specification). Plaid will present this string as a bearer token to all requests made to your Core Exchange API. This encodes the identity of the user and the scope of access granted. |
expires_in | The lifetime of the access token, in seconds. Typically 15 minutes (900 seconds). Plaid checks for expiration before using an access token. If the access token is expired, Plaid will use the refresh token to request a new access token. If your organization expires the token before the stated expiration date, Plaid expects to receive a 401 response with an error code of "602 not authorized". |
id_token | An OIDC ID token. Plaid only reads the sub field from this token.In a deployment with multiple financial institutions, the sub field must be unique to each financial institution. (It doesn't need to be unique to the user across all financial institutions.) |
refresh_token | An opaque string (likely a JWT) that can be used to request a new access token. Plaid will use this to fetch data periodically long after the original access token expires. See the refresh flow section for more information. Plaid doesn't recommend setting an inactivity timeout for the refresh token because it's not a good indicator of whether a user is active with a Plaid partner. For example, some Plaid partners can trigger Plaid to call the Core Exchange endpoint /accounts/{accountID} infrequently for large transactions. |
Example
Your response:
1{2 "access_token": "agstynmdygjdghabrgraeh...",3 "expires_in": 900,4 "id_token": "snsyjrhvjdtvyjvsgcegaethstj...",5 "refresh_token": "dhcsrtjsrgayvkdisfdgntshstu..."6}
After it receives this response, Plaid has everything it needs to access your Core Exchange API.
Error handling
How to handle errors that occur during the authorization flow.
Incorrect redirect URI
If the request fails due to an incorrect, missing, invalid, or mismatched redirect_uri
,
notify Plaid of the error and do not redirect the user to the redirect_uri
.
We recommend displaying an error page to notify the user that an error has occurred.
User cancellation
If the user cancels the request or if the request fails for any other reason other than an incorrect URI, include the following required query parameters with the request. (Please see the OAuth spec for a complete list of possible parameters.)
Expired access token
If Plaid sends an expired access_token
for any reason, send a 401 response with an error code of "602 not authorized".
Query parameter | Description |
---|---|
error | The reason for the error. See the Errors table below for a list of possible errors. |
state | The opaque string Plaid passed as the state parameter in the authorization_endpoint redirect step. |
Errors
See the table below for a full list of possible errors, as defined in the OAuth spec.
Parameter | Description |
---|---|
invalid_request | The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. |
unauthorized_client | The client is not authorized to request an authorization code using this method. |
access_denied | The resource owner or authorization server denied the request. |
unsupported_response_type | The authorization server does not support obtaining an authorization code using this method. |
invalid_scope | The requested scope is invalid, unknown, or malformed. |
server_error | The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.) |
temporarily_unavailable | The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code can't be returned to the client via an HTTP redirect.) |
Example
Your response:
1https://cdn.plaid.com/link/v2/stable/oauth.html?error=access_denied&state=eyJvYXV0aF9zdGF0ZV
Refresh flow
For some use cases, Plaid needs to periodically fetch fresh data on behalf of the user. To get a new access token, Plaid makes another request to your token_endpoint
with a different set of parameters.
Note: The request body will be encoded in the application/x-www-form-urlencoded
format.
Body parameters
Body parameter | Value | Description |
---|---|---|
grant_type | refresh_token | Specifies that Plaid is requesting a new access token to replace the expired access token. |
refresh_token | Example: dhcsrtjsrgayvkdisfdgntshstu... | The refresh token you issued to Plaid. Note: Plaid recommends setting the expiration at 13 months. This allows you to avoid running into expiration issues during time-sensitive intervals (for example, on tax day). |
Example
Plaid's request (using basic authentication):
1curl --request POST 'https://auth.firstplatypusbank.com/oauth2/v1/token' \2--header 'Content-Type: application/x-www-form-urlencoded' \3--header "Authorization: Basic YzVhNTI0NWIwNjJiZjg0MjBkMTFhYjQzNjFiMjhhMTU6clZYWU9vUVM0ckhVRzc5bl80OGFs"4--data-raw '{5 "grant_type": "refresh_token",6 "refresh_token": "dhcsrtjsrgayvkdisfdgntshstu..."7}'
Your response:
1{2 "access_token": "lngarogglkcangasgabba...",3 "expires_in": 900,4 "id_token": "snsyjrhvjdtvyjvsgcegaethstj..."5}
See the previous section for descriptions of these response parameters.
Error handling
See the table below for a full list of possible errors that may occur during the refresh flow. (Note: These errors do not appear in the OAuth spec.)
Parameter | Description |
---|---|
invalid_request | The request is missing a required parameter. |
invalid_client | Client authentication failed. |
invalid_grant | The provided authorization grant or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client (rely on error description from FIs to further break this out). |
unauthorized_client | The authenticated client is not authorized to use this authorization grant type. |
unsupported_grant_type | The authorization grant type is not supported by the authorization server. |
invalid_scope | The requested scope is invalid, unknown, or malformed. |
App2app
App2app is a mechanism that allows mobile apps performing OAuth2 or OpenID Connect based authentication to offer a much simpler, faster flow if the user already has an app provided by the authorization server owner installed on their mobile device.
Follow the steps below to implement App2app with your Core Exchange API:
1. Set up app deep link URLs
Set up claimed HTTPS URLs so that the OAuth redirect launches the app (if installed) instead of the mobile web page. Ensure fallback to web if the app is not installed or is not available. (For example, if the user is on a desktop.)
See the resources below for instructions on how to set up deep link URLs:
- iOS: Universal links
- Android: App Links
2. Set up in-app flow to issue OAuth authorization code
- Native experience (Recommended): Build a fully in-app flow whereby the users completes the authentication flow and the authorization code is issued from within the app, before redirecting back to Plaid.
- Semi-native experience (Alternative): If a fully native experience cannot be resourced we can discuss alternative options, but there will be UX trade-offs.
3. Provide the authorization endpoint redirect URLs to Plaid
Plaid recommends that the data partner provides Plaid with two redirect URLs:
- An App2app flow redirect URL
- A regular web-based flow redirect URL
This allows Plaid to control the user path and isolate any issues that may arise. (For example, if a specific developer ("app") incorrectly implements the App2app flow.)