Authentication
Building Plaid Exchange OAuth
Overview
This section will help you prepare your OAuth 2.0 provider for connecting to Plaid.
Prepare your OAuth 2.0 server
If you are using your existing OAuth identity provider. (For example, Okta, Auth0, Ping Identity, Azure Active Directory, AWS Cognito), please prepare all the URLs and settings required for access. This include firewall rules, scopes and audiences. Initially have these URLs ready:
End Point | Description |
---|---|
authorization_endpoint | Your OAuth landing page, where users can sign in and generate a code for Plaid |
token_endpoint | The token exchange endpoint where Plaid can use the code to generate an id_token , access_token and refresh_token |
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.
If these are not options, there is the option of building a net new provider to support Plaid Exchange.
Note: OIDC Discovery (Well Known Config) and JWKS are not supported in Plaid Exchange
Issue Plaid a client ID and client secret
In order to allow Plaid to authenticate its request for an access token, you will need to issue a client ID and client secret. You may create the client ID and client secret using your preferred method, but we provide some guidance in this guide. Once you have created a client ID and client secret, provide them to your Plaid contact.
Authorization flow overview
Once you have a 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 (unique consistency key).
(This described authentication flow conforms to commonly implemented patterns for the OIDC spec. Plaid welcomes partner feedback.)
Client ID and client secret
In order to register an application for your server, you will need to create a client ID and client secret. These will be shared with Plaid so that the Plaid can identify itself. Below, you will find best practices and code samples to help you create a client ID and client secret.
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.
How to create a client ID
One way to create a client ID is to use a random 32-character hex string. See the code samples below:
1require('crypto').randomBytes(16).toString('hex');
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).
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.
See the code samples below:
1require('crypto').randomBytes(32).toString('hex');
Authorization flow
Plaid redirects the end user
When your user first initiates the process of linking their account, Plaid redirects their browser to the authorization_endpoint
. Plaid's redirect includes these 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. |
client_id | A client ID | The client ID you issued to Plaid. |
state | An opaque string | Plaid generates this. Your organization will return the same string when redirecting to the redirect_uri . |
institution_id | ID representing the data partner/FI | This is a Plaid assigned ID that represents your organization |
application_id | ID representing the requesting application | A Plaid assigned ID that represent the application requesting access. Can be used in combination with Permissions Management. |
scope | (OPTIONAL) Set of scope string: http://plaid.test | The set of scopes Plaid requests access to. |
audience | (OPTIONAL) Set of audience strings: openid offline_access customScope | The set of audiences Plaid requests access to. |
code_challenge | (OPTIONAL) Challenge string | Provides the code assigned to Plaid to start PKCE flow. Generated with code_verifier |
code_challenge_method | (OPTIONAL) Defines the PKCE method :S256 | Provides the PKCE method. |
Optional fields can be requested, please contact Plaid to learn more.
Example
Plaid's redirect:
1https://auth.firstplatypus.com/oauth2/v1/authorize?response_type=code&redirect_uri=https%3A%2F%2Fcdn.plaid.com%2Flink%2Fv2%2Fstable%2Foauth.html&scope=openid%20offline_access&client_id=c5a5245b062bf8420d11ab4361b28a15&state=eyJvYXV0aF9zdGF0ZV
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.
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. |
Auth Example
Your response:
1https://cdn.plaid.com/link/v2/stable/oauth.html?code=1284918391&state=eyJvYXV0aF9zdGF0ZV
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 error handling section for more information.
Token Flow
Plaid sends a request to your token_endpoint
.
Unlike the two previous steps, the request to 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 also send the authorization code (code
) in the body of the request and expects to receive an access_token
, id_token
, and refresh_token
in your response.
Body parameters
Body parameter | Value | Comment |
---|---|---|
grant_type | authorization_code | The type of grant Plaid is exchanging for an access token. (In this case, an authorization code.) |
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. |
code | The code you sent to Plaid in the previous step | The temporary authorization code Plaid is exchanging for the access token. |
code_verifier | (OPTIONAL) code used to generate challenge | A code provided to Plaid or generated by Plaid to use as the key for PKCE challenge codes |
Token request example
Plaid's request:
1curl --request POST 'https://auth.firstplatypusbank.com/oauth2/v1/token' \2--header 'Content-Type: application/json' \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
parameters from Plaid's request all match the expected values. Your response to this request contains everything that Plaid needs to later access your Plaid Exchange API:
Property | Description |
---|---|
access_token | An opaque string (likely a JWT structured according to the OAuth 2.0 specification). Plaid will present this string as a bearer token to all requests made to your Plaid Exchange API. This encodes the identity of the user and the scope of access granted. |
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 Plaid Exchange endpoint /accounts/{accountID} infrequently for large transactions. |
user_id | (Optional if id_token is not possible) A unique identifier that replaces the id_token.sub |
Token response example
Your response:
1{2 "access_token": "agstynmdygjdghabrgraeh...",3 "id_token": "snsyjrhvjdtvyjvsgcegaethstj...",4 "user_id": "2347456437346745", // Optional, see above5 "refresh_token": "dhcsrtjsrgayvkdisfdgntshstu..."6}
If user_id
and id_token
are not present, the final attempt to resolve the unique consistency key will be via the FDX endpoint called /customer/current
. The response is listed below.
1{2 "customerId": "2347456437346745"3}
After it receives this response, Plaid has everything it needs to access your Plaid Exchange API.
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.
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). |
Refresh example
Plaid's request:
1curl --request POST 'https://auth.firstplatypusbank.com/oauth2/v1/token' \2--user "plaid:rVXYOoQS4rHUG79n_48al"3--header 'Content-Type: application/json' \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
How to handle an error that occurs 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.)
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
Alternative auth methods
Plaid provides legacy support for existing integrations using non-OAuth authentication methods. However, these methods are deprecated, and new PX integrations must use OAuth for authentication.
OAuth is the preferred security method. However there are many existing integrations using the MFA/OTP options for authenticating a user. Plaid will continue to support these methods, but they are deprecated for new users.
Please work with Plaid if you have a limitation to OAuth and must use OTP or MFA.
This API reference describes the following alternative security endpoints with the following workflow:
POST /users/auth_token: this endpoint is used for basic as well as multi-factor authentication.
- For basic, it returns an authorization response with an auth token for the user.
- For multifactor authentication flows, the endpoint responds with one of the following:
Based on the multifactor challenge type, Plaid then calls one or both of the following:
- POST /users/{user_id}/sendOtp: Plaid sends this for
OTP
flows only. - POST /users/{user_id}/2fa
For this endpoint, depending on the multi-factor authentication flow, Plaid sends one of the following:
- OTP validation request: For
OTP
orTOTP
. - KBA validation request: For
KBA
. If the validation is successful, this endpoint returns an authorization response with an auth token for the user.
- OTP validation request: For
- POST /users/{user_id}/sendOtp: Plaid sends this for
Request an auth token for a user
Plaid uses the POST /users/auth_token
endpoint to request an auth token for a user. This endpoint is the essential API method for authenticating user credentials and is a part of all non-OAuth authentication flows documented here, including multifactor flows.
- For an overview of the basic flow of this endpoint, see Alternative auth methods.
- For an example request and response, see the following section:
POST /users/auth_token
Provides Plaid a mechanism by which a credentials pair can be authenticated and exchanged for a user ID and access token authorized to request user-specific resources on behalf of the partner institution’s customer. This call may result in a 2-factor challenge.
users/auth_tokenusername
password
institution_id
1curl --location --request POST2'https://your-institution.com/users/auth_token/' \3--header 'Content-Type: application/x-www-form-urlencoded' \4--header 'X-PLAID-CLIENT-ID: example_ID' \5--header 'X-PLAID-SECRET: example_secret' \6--header 'X-PLAID-VERSION: 2021-03-26' \7--header 'Accept: application/json' \8--data-urlencode 'username=user123&password=pass123&institution_id=inst123'
Responses
Successful responses include 200
for basic authentication and 202
for multifactor authentication.
200 OK
For basic authentication, POST users/auth_token
returns a 200 response with the access token:
Response fields and example
user_id
auth_token
1{2 "user_id": "YRQ8PPaohJ",3 "auth_token": "1fce3854-0134-44ac-a1e1-d84ed09fec10"4}
Was this helpful?
202 Accepted
For more information, see the following multifactor authentication section.
400 Bad Request
Response indicating the presence of an error.
request_id
error
Was this helpful?
401 Not Authorized
Response indicating the presence of an error.
request_id
error
Was this helpful?
403 Forbidden
The user’s account is locked, typically due to excessive incorrect authentication attempts. This response will trigger messaging to the user indicating that the account has been temporarily locked and will advise the user to contact the institution.
405 Not Allowed
This response should be used to indicate that the user’s account is not permitted to participate in aggregation, typically because the user must accept a license or terms of use. This will trigger messaging to the user indicating that the account is not yet authorized for online use and will direct the user to visit the partner institution’s online portal for further guidance. Plaid recommends that whatever pending terms or agreements that block this use case be presented to the user immediately upon login.
503
Signifying the institution is currently unavailable to respond to the request.
error
retry_at
date-time
id
message
request_id
Was this helpful?
Multifactor authentication
If the response from POST /users/auth_token
is 202 Accepted
, then Plaid must challenge the user with a multifactor authentication flow.
The 202 response indicates that presented credentials are accepted for further processing. It does not indicate that the presented credentials are correct. For an overview of the multifactor authentication flow, see Alternative auth methods.
The 202 response body is one of the following:
MfaOtpEscalationChallenge
for temporary, out-of-band password 2FA authentication. This indicates Plaid next requestsPOST /users/{user_id}/sendOtp
thenPOST /users/{user_id}/2fa
.MfaKbaEscalationChallenge
for knowledge-based 2FA authentication. This indicates Plaid next requestsPOST /users/{user_id}/2fa
.MfaTotpEscalationChallenge
for temporary, on-hand password 2FA authentication. This indicates Plaid next requestsPOST /users/{user_id}/2fa
.
See the following sections for details.
202 response for OTP
If Plaid receives the MfaOtpEscalationChallenge
response (the most common scenario) from POST /users/auth_token
, Plaid:
- Prompts the user in Plaid Link to select how they want their OTP sent, displaying the methods the partner indicates it supports in the
MfaOtpEscalationChallenge
response. For example,voice
orsms
. - Sends the
POST /users/{user_id}/sendOtp
request indicating the partner should send the OTP to the user's selected method. For more information see Trigger OTP API method. - After receiving a 200 response, prompts the user in Plaid Link to fill in the OTP and waits for them to fill it in.
- Sends the OTP the user entered for validation using the
POST /users/{user_id}/2fa
request. For more information see Validate 2FA.
MfaOtpEscalationChallenge response
Prompts user to choose how to receive their out-of-band one-time passcode as part of an MFA escalation
user_id
challenge
id
type
fido2
otp
kba
push
totp
prompt
send_methods
1
1{2 "user_id": "example_id_string",3 "challenge": {4 "id": "example_id_string",5 "type": "otp",6 "send_methods": [7 {8 "id": "Z9D0iK",9 "mask": "(***) ***-8653",10 "type": "sms"11 },12 {13 "id": "36b4Xo",14 "mask": "j****@p****.com",15 "type": "email"16 }17 ]18 }19}
Was this helpful?
202 response for KBA
If Plaid receives the MfaKbaEscalationChallenge
response from POST /users/auth_token
, Plaid:
- Prompts the user in Plaid Link to enter answers to the questions that Plaid received in the
MfaKbaEscalationChallenge
response. - Sends the answers the user entered for validation using the
POST /users/{user_id}/2fa
request. For more information see Validate 2FA.
MfaKbaEscalationChallenge response
Questions the user must answer.
user_id
challenge
id
type
fido2
otp
kba
push
totp
1{2 "user_id": "example_id",3 "challenge": {4 "id": "Adf2345",5 "type": "kba",6 "questions": [7 {8 "id": "Z9D0iK",9 "text": "What city were you born in?"10 },11 {12 "id": "ch7SbY",13 "text": "Where did you go to high school?"14 },15 {16 "id": "36b4Xo",17 "text": "What is your mother's maiden name?"18 }19 ]20 }21}
Was this helpful?
202 response for TOTP
If Plaid receives the MfaTotpEscalationChallenge
response from POST /users/auth_token
,
this indicates that the partner doesn't have to send
a temporary password because the user already has the temporary password generator on hand, for example in the form of an
authenticator app that displays a new passcode every 60 seconds. If Plaid receives this response, Plaid:
- Prompts the user in Plaid Link to fill in the TOTP and waits for them to fill it in.
- Sends the TOTP the user entered for validation using the
POST /users/{user_id}/2fa
request. For more information see Validate 2FA.
MfaTotpEscalationChallenge response
Prompts for a temporary password from an on-hand password generator.
user_id
challenge
type
fido2
otp
kba
push
totp
prompt
1{2 "user_id": "example_id",3 "challenge": {4 "id": "Adf2345",5 "type": "totp",6 "prompt": "Enter your one-time password."7 }8}
Was this helpful?
401 Unauthorized
Response indicating the presence of an error.
request_id
error
Was this helpful?
403 Forbidden
This response indicates the user’s account is locked, typically due to excessive incorrect authentication attempts. This response will trigger messaging to the user indicating that the account has been temporarily locked, and will advise the user to contact the institution.
405 Not Allowed
This response indicates that the user’s account is not permitted to participate in aggregation, typically because the user must accept a license or terms of use. This will trigger messaging to the user indicating that the account is not yet authorized for online use, and will direct the user to visit the partner institution’s online portal for further guidance.
Plaid recommends that whatever pending terms or agreements that block this use case be presented to the user immediately upon login.
Trigger OTP
POST /users/{user_id}/sendOtp
In the case of OTP authentication, provides Plaid with a mechanism to trigger partner-initiated delivery of OTP to the user’s selected send method.
users/{user_id}/sendOtpuser_id
path
1curl -X POST 'https://your-institution.com/users/example_user_id_1/sendOtp' \2 --header'X-PLAID-CLIENT-ID: PLAID' \3 --header 'X-PLAID-SECRET: example_secret' \4 --header 'X-PLAID-VERSION: 2021-03-26' \5 --header 'Accept: application/json' \6 --header 'Content-Type: application/x-www-form-urlencoded' \7 --data-urlencode 'challenge_id=36b4Xo&send_method_id=Z9D0iK' \
Responses
200 OK
This response indicates that the send method was acceptable and the partner institution will transmit the passcode to the user. No response body is required.
400 Bad Request
Response indicating the presence of an error.
request_id
error
Was this helpful?
503
Signifying the institution is currently unavailable to respond to the request.
error
retry_at
date-time
id
message
request_id
Was this helpful?
Validate 2FA
POST /users/{user_id}/2fa
POST /users/{user_id}/2fa
receives and validates the user's response to the escalation challenge.
This is the final endpoint Plaid request in all multi-factor flow types.
Plaid sends one of the following request bodies to this endpoint:
ValidateOtpChallengeRequest
ValidateKbaChallengeRequest
See the following sections for details.
Validate TOTP or OTP
ValidateOtpChallengeRequest
Request to validate TOTP or OTP code.
challenge_id
passcode
1{2 "passcode": "123456"3}
Was this helpful?
1curl --location --request POST2'https://your-institution.com/users/user123/2fa/' \3--header 'Content-Type: application/x-www-form-urlencoded' \4--header 'X-PLAID-CLIENT-ID: example_ID' \5--header 'X-PLAID-SECRET: example_secret' \6--header 'X-PLAID-VERSION: 2021-03-26' \7--header 'Accept: application/json' \8--data-urlencode 'passcode=123456&challenge_id=example_id'
Validate KBA
ValidateKbaChallengeRequest
Request to validate KBA challenge answers.
challenge_id
answers
question_id
text
1{}
Was this helpful?
1curl --location --request POST 'https://your-institution.com/users/user123/2fa/' \2--header 'Content-Type: application/x-www-form-urlencoded' \3--header 'X-PLAID-CLIENT-ID: example_ID' \4--header 'X-PLAID-SECRET: example_secret' \5--header 'X-PLAID-VERSION: 2021-03-26' \6--header 'Accept: application/json' \7--data-urlencode 'challenge_id=string' \8--data-urlencode 'answers[0].question_id=string' \9--data-urlencode 'answers[0].text=San Francisco' \10--data-urlencode 'answers[1].question_id=string2' \11--data-urlencode 'answers[1].text=Billings High School'
Responses
200 OK
The challenge response was correct. The partner returns the access token in the AuthenticationResponse
.
Response fields and example
user_id
auth_token
1{2 "user_id": "YRQ8PPaohJ",3 "auth_token": "1fce3854-0134-44ac-a1e1-d84ed09fec10"4}
Was this helpful?
400 Bad Request
Response indicating the presence of an error.
request_id
error
Was this helpful?
401 Not Authorized
Response indicating the presence of an error.
request_id
error
Was this helpful?
503
Signifying the institution is currently unavailable to respond to the request.
error
retry_at
date-time
id
message
request_id