Plaid logo
Docs
ALL DOCS

Link

  • Overview
Platforms
  • Web
  • iOS
  • Android
  • React Native
  • Hosted Link
Core Link functionality
  • OAuth guide
  • Update mode
  • Preventing duplicate Items
  • Data Transparency Messaging migration
  • Returning user experience
Additional Link modes
  • Embedded Link
  • Multi-Item Link
  • Link Recovery (beta)
  • Modular Link (UK/EU only)
Optimizing Link
  • Optimizing Link conversion
  • Link analytics and tracking
  • Pre-Link messaging
  • Customizing Link
  • Choosing when to initialize products
Errors and troubleshooting
  • Troubleshooting
  • Handling an invalid Link Token
  • Institution status in Link
Legacy flows
  • Legacy public key integrations
  • Link Token migration guide
  • Webview integrations
Plaid logo
Docs
Close search modal
Ask Bill!
Ask Bill!
Hi! I'm Bill! You can ask me all about the Plaid API. Try asking questions like:
  • How do I fix an Item in ITEM_LOGIN_REQUIRED state?
  • What's the difference between Plaid Identity and IDV?
  • Why is /transactions/sync/ better than /get?
Note: Bill isn't perfect. He's just a robot platypus that reads our docs for fun. You should treat his answers with the same healthy skepticism you might treat any other answer on the internet. This chat may be logged for quality and training purposes. Please don't send Bill any PII -- he's scared of intimacy. All chats with Bill are subject to Plaid's Privacy Policy.
Plaid.com
Log in
Get API Keys
Open nav

Link token migration guide

How to migrate your application from the public key to a Link token

Support for the public-key based integration mode will end on January 31, 2025. All customers still using the public key-based method of integration must switch to using Link tokens by this date, as public keys will no longer work to launch Link sessions beginning in February 2025.

Introduction

Plaid has introduced a new link_token, which replaces the static public_key. This is an improvement that provides better error validation, more advanced security, and enables Link event logs to be surfaced in the Plaid Dashboard. While Plaid does not plan to discontinue support for existing public_key integrations, it is recommended that you upgrade your integration to use a link_token, as it enables enhanced capabilities, and future Plaid development and features will be based on the link_token infrastructure. Link tokens are also required for new OAuth integrations.

If you are unable to migrate to Link tokens at this time, see maintaining a public key integration for instructions on working with legacy public keys.

This guide covers the client and server-side changes required to implement the new link_token. Here's an overview of the updates before we dive into the details.

The Plaid flow begins when your user wants to connect their bank account to your app.
Step  diagram
1Call /link/token/create to create a link_token and pass the temporary token to your app's client.
Step 1 diagram
2Use the link_token to open Link for your user. In the onSuccess callback, Link will provide a temporary public_token. This token can also be obtained on the backend via `/link/token/get`.
Step 2 diagram
3Call /item/public_token/exchange to exchange the public_token for a permanent access_token and item_id for the new Item.
Step 3 diagram
4Store the access_token and use it to make product requests for your user's Item.
Step 4 diagram

What's new

  • Link will now be initialized with a new link_token. The link_token replaces all previous methods of initializing Link, including the public_key (for initial Link), the public_token (for update mode), and the payment_token (for Payment Initiation).
  • The new endpoint to create the link_token is /link/token/create.
  • The INVALID_LINK_TOKEN error code is now available to gracefully handle invalidated tokens.
  • Link events from sessions created with the new link_token will be surfaced in the Logs section of the Dashboard. However, Link events from sessions created with the public_key will not.

Link tokens

The link_token is a new type of token that is created by your app's server and passed to your app's client to initialize Link. The Link configuration parameters that were previously set within Link itself are now set via parameters passed to /link/token/create and conveyed to Link via the link_token. If these configurations are still set client-side when using the link_token, they will not have any effect on Link behavior.

Update your integration

The overall process for updating your integration is:

  1. Update your server to create a link_token.
  2. Update your client to pass the link_token and handle INVALID_LINK_TOKEN errors.
  3. Ensure you have updated all Link entry points, including those for update mode.
  4. Test your integration.
  5. Update any callsites that use the public_key for authentication to use the client_id and secret instead, then re-test those callsites.
  6. Disable the public_key.

Detailed instructions for each step can be found below.

Update your server

Add a new authenticated endpoint to your app's server to create a link_token by calling /link/token/create.

Select Language
1app.post('/api/create_link_token', async function (request, response) {
2 // Get the client_user_id by searching for the current user
3 const user = await User.find(...);
4 const clientUserId = user.id;
5 const request = {
6 user: {
7 // This should correspond to a unique id for the current user.
8 client_user_id: clientUserId,
9 },
10 client_name: 'Plaid Test App',
11 products: ['transactions'],
12 language: 'en',
13 webhook: 'https://webhook.example.com',
14 redirect_uri: 'https://domainname.com/oauth-page.html',
15 country_codes: ['US'],
16 };
17 try {
18 const createTokenResponse = await client.linkTokenCreate(request);
19 response.json(createTokenResponse.data);
20 } catch (error) {
21 // handle error
22 }
23});

Many of the parameters to /link/token/create are the same as parameters previously set in Link. Aside from the change to snake case from camelCase, there are a few substantive differences, summarized below. Note that these bullets are only a summary; for the full /link/token/create endpoint definition, see the API Reference.

  • A new required parameter, user.id, has been added. This should be a unique identifier, such as the user ID of the end user in your application. It should not contain personally identifiable information, such as a phone number or email address.
  • language and country_codes, which were previously optional, are now required.
  • accountSubtypes has been replaced by the account_filters parameter, and its syntax has changed.

In addition, there are a few differences relevant specifically to European integrations:

  • The oauthNonce parameter is no longer used, since it is effectively replaced by user.id.
  • For the Payment Initiation product, The paymentToken is no longer used, and /payment_initiation/payment/token/create has been deprecated. Instead, the payment_id should be provided to /link/token/create via the payment_initiation.payment_id parameter. Initializing Link with the returned link_token will launch the Payment Initiation flow.
Authenticate your app

The endpoint used to create a link_token should only be available to users that are logged in to your app. Once your user is logged in, pass an identifier that uniquely identifies your user into the user.client_user_id field. The value of this field should not be personally identifiable information such as an email address or phone number. Using user.client_user_id will allow for easier debugging in the Dashboard logs. You will be able to search for Link logs that belong to one of your end users.

As this update involves an additional API call when adding an Item, create a link_token when your user initially visits your app to avoid adding latency to your Link flow.

Update your client

For each of your web and mobile apps, use the new endpoint you created to fetch a link_token, then pass it into one of Plaid's Link SDKs to initialize Link. You can then safely remove the public_key and other client-side configs that are now configured in the /link/token/create request.

If the token expires or the user enters too many invalid credentials, the link_token can become invalidated. If it does get into an invalid state, Link will exit with an INVALID_LINK_TOKEN error code. By recognizing when this error occurs in the onExit callback, you can generate a fresh link_token for the next time your user opens Link.

Update Link web

The code below demonstrates code that passes the new link_token to Link. For more in-depth coverage on how to integrate with Link web, see the Link web docs.

Note that in the error handling section, in order to handle an invalid link_token for Link in the browser, you will need to gracefully clean up the old iframe before reinitializing Link. To do this, use the destroy() method and reinitialize Link with a new link_token in the onExit callback.

1<button id="link-button">Link Account</button>
2<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
3<script type="text/javascript">
4(async function() {
5 const fetchLinkToken = async () => {
6 const response = await fetch('/create_link_token', { method: 'POST' });
7 const responseJSON = await response.json();
8 return responseJSON.link_token;
9 };
10
11 const configs = {
12 // 1. Pass a new link_token to Link.
13 token: await fetchLinkToken(),
14 onSuccess: async function(public_token, metadata) {
15 // 2a. Send the public_token to your app server.
16 // The onSuccess function is called when the user has successfully
17 // authenticated and selected an account to use.
18 await fetch('/exchange_public_token', {
19 method: 'POST',
20 body: JSON.stringify({ public_token: public_token }),
21 });
22 },
23 onExit: async function(err, metadata) {
24 // 2b. Gracefully handle the invalid link token error. A link token
25 // can become invalidated if it expires, has already been used
26 // for a link session, or is associated with too many invalid logins.
27 if (err != null && err.error_code === 'INVALID_LINK_TOKEN') {
28 linkHandler.destroy();
29 linkHandler = Plaid.create({
30 ...configs,
31 token: await fetchLinkToken(),
32 });
33 }
34 if (err != null) {
35 // Handle any other types of errors.
36 }
37 // metadata contains information about the institution that the
38 // user selected and the most recent API request IDs.
39 // Storing this information can be helpful for support.
40 },
41 };
42
43 var linkHandler = Plaid.create(configs);
44
45 document.getElementById('link-button').onclick = function() {
46 linkHandler.open();
47 };
48})();
49</script>
Update Link iOS

The iOS SDK now provides an initWithLinkToken method on both the PLKConfiguration and the PLKPlaidLinkViewController classes that should allow you to easily initialize Link with a link_token.

The code below shows how to initialize Link with the link_token in iOS. For more in-depth coverage on how to integrate with Link iOS, see the iOS docs.

Select Language
1let linkConfiguration = PLKConfiguration(linkToken: "GENERATED_LINK_TOKEN")
2let linkViewDelegate = self
3let linkViewController = PLKPlaidLinkViewController(
4 linkToken: "GENERATED_LINK_TOKEN",
5 configuration: linkConfiguration,
6 delegate: linkViewDelegate,
7)
8if (UI_USER_INTERFACE_IDIOM() == .pad) {
9 linkViewController.modalPresentationStyle = .formSheet;
10}
11present(linkViewController, animated: true)
Update Link Android

The Android SDK exposes a new class called LinkTokenConfiguration. This class accepts the link_token and should be passed into the openPlaidLink method.

The code below demonstrates how to use the LinkTokenConfiguration class to open Link. For more in depth coverage on the Android SDK, see the Android docs.

Select Language
1import android.os.Bundle
2import android.util.Log
3import androidx.appcompat.app.AppCompatActivity
4
5import com.plaid.link.Plaid
6import com.plaid.link.linkTokenConfiguration
7import com.plaid.link.openPlaidLink
8import com.plaid.link.configuration.AccountSubtype
9import com.plaid.link.configuration.LinkLogLevel
10import com.plaid.link.configuration.PlaidEnvironment
11import com.plaid.link.configuration.PlaidProduct
12import com.plaid.link.event.LinkEvent
13import java.util.Locale
14
15class MainActivity : AppCompatActivity() {
16
17 override fun onCreate(savedInstanceState: Bundle?) {
18 super.onCreate(savedInstanceState)
19
20 // Optional
21 Plaid.setLinkEventListener { event -> Log.i("Event", event.toString()) }
22
23 // Open Link – put this inside of a Button / Fab click listener
24 this@MAINACTIVITY.openPlaidLink(
25 linkTokenConfiguration {
26 // required
27 token = "GENERATED_LINK_TOKEN"
28
29 // optional
30 logLevel = LinkLogLevel.WARN // Defaults to ASSERT
31 extraParams = mapOf() // Map of additional configs
32 }
33 );
34 }
35}

Update Link update mode flows

With the introduction of the link_token, /item/public_token/create is deprecated, and Link's update mode is initialized by passing in a link_token rather than a public_token. You can obtain this link_token by calling /link/token/create and providing the user.id of the user whose Item is being updated, along with the access_token for the Item. Make sure to update any update mode flow entry points in addition to updating primary Link flows. For more details and complete sample code, see Updating Items via Link.

1// Initialize Link with the token parameter
2// set to the generated link_token for the Item
3const linkHandler = Plaid.create({
4 token: 'GENERATED_LINK_TOKEN',
5 onSuccess: (public_token, metadata) => {
6 // You do not need to repeat the /item/public_token/exchange
7 // process when a user uses Link in update mode.
8 // The Item's access_token has not changed.
9 },
10 // ...
11});

Test in Sandbox

Once you have updated both your app's client and server, it's time to test that your integration works. The best way to test is by using the test credentials in the Sandbox:

1username: user_good
2password: pass_good

Test your error handling flow for INVALID_LINK_TOKEN by using the Sandbox test credentials to force an error:

1username: user_custom
2password: { "force_error": "INVALID_LINK_TOKEN" }

You can also verify that you have updated correctly by viewing Link event logs in the Plaid Dashboard.

To test your update mode implementation, use the /sandbox/item/reset_login endpoint to force an Item into a state that requires an update, then walk through the test steps above.

Update API endpoints

In order to completely migrate off of the public_key, there are a few Plaid API endpoints that should replace the public_key with the client_id and secret: /institutions/search, /institutions/get_by_id, and /sandbox/public_token/create.

Because the client_id and secret are now used to authenticate the endpoints above, they should only be called from your server. The ability to call them from the client has been removed in the latest client library updates.

Disable the public key

After completing all of the above steps, you can now confidently disable the public_key via the Plaid Dashboard. This can be done on a per-environment basis, with different settings for Sandbox and Production, to help you test your migration. The public_key can also be disabled separately for Link and for the API. Disabling it for Link means you will be required to use the link_token to initialize Link. Disabling it for the API means that you will be required to use the client_id and secret to call /institutions/search, /institutions/get_by_id, and/sandbox/public_token/create.

image of Dashboard UI for disabling the public key

It is recommended you disable the public_key as soon as possible to ensure that you do not accidentally add legacy public_key-dependent code to your application.

Conclusion

Congratulations on upgrading to the new link_token! If you require any help migrating to the link_token integration, please contact Plaid Support for assistance.

Was this helpful?
Developer community
GitHub
GitHub
Stack Overflow
Stack Overflow
YouTube
YouTube
Discord
Discord