Create Profiles with Connect

Overview

Users create and update Profiles by interacting with Basis Connect. All of a business's information is attached to its Profile. When querying the Basis API, Profile objects will be the root of all of a business's resources.

Developers will redirect Users to Connect by generating and embedding URIs in, for example, your onboarding workflow or application dashboard. Connect is an OAuth 2.1 application, and the URI that Developers generate will include various parameters related to client authentication, scope, and application initialization. The Connect user interface handles the entire process of connecting to banks and other data sources.

Generating a URI

Initializing Connect requires generating an initialization token and directing your user to the Connect URI. Constructing the HTTPS request entails (a) populating the query parameters after (b) generating an initialization token.

Query parameters

The following query parameters form the request:

ParameterRequiredDescription
response_typeOAuth response code delivery method.code is the only supported response_type.
client_idThe developer's client ID, issued by Basis.
scopeOAuth scope. profile:read is the only currently supported scope, denoting read-only access to the user's Basis Profile.
redirect_uriThe URI for the user to be redirected upon completing the Connect flow. This must be one of the URIs registered with Basis when creating the client.
stateOAuth 2.0 state parameter. Optional but recommended to prevent CSRF attacks as users return to your workflow. See this OAuth guide for more information.
code_challengeOAuth parameter facilitating Proof Key for Code Exchange protocol. See this section of the OAuth guide for more information.

NOTE Basis does not support the code_challenge_method parameter: S256 will always be assumed.
init_tokenDetail below.

For deeper understanding of the query parameters, please review the OAuth 2.1 spec or the OAuth 2.0 Simplified guide.

Initialization token

The initialization token is a JWT signed with your client_secret.

Initialization token header

{
	"alg": "HS512",
	"kid": "06914d28-f034-4d52-b048-e11024957c11",
	"typ": "JWT"
}

Note that the value for kid should be your client_id.

Initialization token payload example

{
	"exp": 1516249022,
	"iat": 1516239022,
	"platform_id": "4f2cc69b-576d-4eef-8fde-c36f1841b434",
	"client_id": "06914d28-f034-4d52-b048-e11024957c11",
	"user_email": "[email protected]",
	"user_name": "Garfield",
	"company_ein": "12-3456789",
	"company_name": "Lasagna Enterprises",
	"native_user_id": "555123",
	"native_company_id": "333456"
}

The payload includes the following parameters:

ParameterTypeNote
expstring<timestamp>Token expiration time, as specified by RFC 7519.
iatstring<timestamp>Token issuance time, as specified by RFC 7519.
platform_idstring<uuid>Identifier of the banking platform to connect the user to.
client_idstring<uuid>Identifier of the client initializing Connect.
user_emailstring<email>Email of the user completing Connect.
user_namestringFull name of the user completing Connect.
company_einstring<pattern:\d{9}>EIN of the business for which a Profile is being created.
company_namestringFull legal name of the business for which a Profile is being created.
native_user_idstringA user identifier that is meaningful in the Developer's schema, e.g. a primary key for this user in your database. This can assist in reconciling Basis profiles to your users.
native_company_idstringA company identifier that is meaningful in the Developer's schema, e.g. a primary key for this company.

The initialization token can be categorized into several types of information:

CategoryParametersPurpose
Session informationexp,iat,platform_id,client_idUsed to confirm that the token has not expired, authenticate the client, and initialize Connect for a particular platform.
Profile constructionuser_email,user_name,company_ein,
company_name
Critical for fraud prevention and ensuring resilient connections to data sources.
Reconciliationnative_user_id,native_company_idAssist the Developer in associating the Profile information with a user or company record in their own application. It is also helpful in support and debugging interactions with Basis.

Generating Initialization Tokens

The following TypeScript code will generate an initialization token for a redirect URI.

Install packages

npm install jsonwebtoken @types/jsonwebtoken

Code

After the jsonwebtoken package is installed, you can use this snippet to generate a token. Insert your Basis client credentials where indicated.

import { Buffer } from 'buffer';
import jwt from 'jsonwebtoken';

const BasisCredentials = {
  // replace with credentials provided by Basis
  clientId: 'CLIENT_ID',
  clientSecret: 'CLIENT_SECRET',
}

const secret = Buffer.from(BasisCredentials.clientSecret, 'base64');
const payload = {
  client_id: BasisCredentials.clientId,
  user_name: "Jane Doe",
  user_email: "[email protected]",
  company_name: "Acme Property Holdings, LLC.",
  company_ein: "881231234",
  native_user_id: 'user-999',
  native_company_id: 'company-456',
  platform_id: "70a5e5d3-00df-50f2-9f19-544d1f54c4bf",  // use GET /institutions
}

const token = jwt.sign(payload, secret, {
  algorithm: 'HS512',
  expiresIn: '1h',
});

With an encoded token, you can now create a URI which can be embedded in your application. When this URI is navigated to, it will initialize a session in Connect which will guide a user through connecting their accounts at the institution indicated by platform_id.

const redirect = new URL('https://connect.development.usebasis.co/oauth');
redirect.searchParams.append('client_id', BasisCredentials.clientId);
redirect.searchParams.append('scope', 'profile:read');
redirect.searchParams.append('code_challenge', codeChallenge);
redirect.searchParams.append('redirect_uri', returnUri);
redirect.searchParams.append('state', state);
redirect.searchParams.append('init_token', token);

// the URL object can be rendered with toString()
const href = redirect.toString();

OAuth Exchange

In addition, Connect uses the Proof Key for Code Exchange (PKCE) protocol, which requires that the client generate and store a code_challenge and code_verifier. We recommend using a library in your preferred language to manage the OAuth process end-to-end, and perform PKCE.

Once the Connect URI is generated, it can be embedded in your product's UI to direct users to create their business Profile and establish connections. The URI is used with an HTTPS request:

GET /oauth
HOST: connect.development.usebasis.co

The initialization tokens expire, so it is important to generate the token and Connect URI at a time when it is expected to be used. The expiration time is defined by the developer when signing the JWT. We recommend using a short expiry when possible, ideally not exceeding 1 hour.

After the user authorizes your client to access their profile, an auth_code is generated and returned. The auth_code can then be exchanged for an access_token, refresh_token and profile_id by calling POST /oauth/token with the authorization_code grant type and the code_verifier. It is important to persist the refresh_token and profile_id so that you can request new access_tokens in the future.

The access_token can then be used to query the Basis API for the newly created profile. Since theaccess_token expires after 60 minutes, the refresh_token should be used to request a new access_token by calling POST /oauth/token with the refresh_token grant type.

OAuth Errors

A number of errors can occur when initializing Connect. For example, the initialization token could be malformed or expired. In these cases, Connect will attempt to redirect the user to the specified redirect URI immediately after initialization, and will encode error information in the query parameters of the redirect URI. General information about this behavior can be found in section 4.1.2.1 of the OAuth specification.

Note: This behavior will not apply when the redirect URI is malformed or incorrect (i.e. not one of your registered redirect URIs) because it is impossible for Connect to safely redirect the user to your domain.

ParameterRequiredDescription
errorRequiredError code indicating the type of error that occurred. See values below.
error_descriptionOptionalHuman-readable description providing more details about the error.
error_uriOptionalURI pointing to a web page with information about the error.
stateRequiredThe client-provided state parameter to maintain state between the request and callback.

The error parameter will be one of the following values:

  • invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the error_description for more details.
  • unauthorized_client: The client is not authorized to request an authorization code using this method.
  • access_denied: The resource owner (e.g. a Connect user) 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.
  • temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.

For example, if a user attempts to initialize Connect with an expired initialization token, you will receive the following redirect:

http://example.com/land?error=invalid_request&error_uri=https%3A%2F%2Fwww.ietf.org%2Farchive%2Fid%2Fdraft-ietf-oauth-v2-1-11.html%23section-4.1.2.1&state=d0fc31e4-3613-4810-ada7-821a74e256ba&error_description=Request+included+expired+Initialization+Token.

This redirect encodes the following information:

  • error: invalid_request
  • error_uri: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.2.1
  • error_description: Request included expired Initialization Token.
  • state:d0fc31e4-3613-4810-ada7-821a74e256ba

You can ignore this error information or consume it as you see fit (e.g. by logging or raising an error).