Using IDPartner Verifications with the Stytch API

Using IDPartner Verifications with the Stytch API

We are huge fans of what Stytch is doing to step-change the developer experience around authentication, identity, and access management. If you’re not familiar, Stytch offers all sorts of options that make it easy for you to do auth the way you need to for your business, including direct API integration, frontend or backend SDKs, and out-of-the box components.

Stytch and IDPartner: A Complementary Pair

Authentication is not identification or identity verification: sometimes, you might want to know that the end user you’re onboarding is exactly who they claim to be. You don’t actually need to scan their drivers license or passport - and, in fact, in the world of deepfakes powered by AI those solutions are becoming less and less reliable. 

IDPartner relies on well capitalized, well regulated banks to solve those problems for the smaller businesses of the world who, nevertheless, want to protect themselves from fraud. A verification from a bank that “yes this person could log into a bank account” and “yes this person passed a series of “know your customer checks” in order to open a bank account is often enough trust. It helps to dramatically lower fraud in countries such as Canada, Sweden, and Norway. 

So let’s say you want to reduce fraud. Let’s say you want to add a bank-grade identity verification into your Stytch-powered identity solution when you’re creating a user. Here’s how to insert that confidence into your Stytch API.

Creating Bank-Verified Stytch Users

Stytch requires you to obtain API keys from their dashboard to authenticate requests to their API. To create a new user with bank-based ID, you would use the Stytch Create User API along with ours.

You also need to set up a web server and an instance of the IDPartner Client to verify the user identity and get the trusted claims from the bank.

Finally, populate your call to the Stytch API with the trusted claims coming back from the bank - you can even choose to name the external_source with the name of IDPartner or the name of the bank using the trusted_metadata field, if you would like to know the provenance of your data.

This is how the code would look:


const express = require('express');

const Stytch = require('stytch');

const IDPartnerClient = require('@idpartner/node-oidc-client');

const port = 3000;

// Init the Stytch client with the Stytch API keys

const stytchClient = new Stytch.Client({

  project_id: 'PROJECT_ID',

  secret: 'SECRET',


// Init the IDPartner client with the client ID and client secret issued by IDPartner.

const idpartnerClient = new IDPartnerClient({

  client_id: 'CLIENT_ID',

  client_secret: 'CLIENT_SECRET',

  // This must go to /oauth/callback endpoint.

  // See implementation below.

  callback: `http://localhost:${port}/oauth/callback`


const app = express();

// Endpoint to start the verification flow

app.get('/oauth', async (req, res, next) => {

  try {

    // Store bank (issuer) selected by the end user.

    // This is used in the callback endpoint to get the userinfo.

    req.session.issuer = req.query.iss;

    // Generate and store state, nonce and code verifier (for PKCE)

    const proofs = idpartnerClient.generateProofs();

    req.session.proofs = proofs;

    // Get and redirect to the authorization URL

    const scope = 'openid email profile';

    const extraAuthorizationParams = { prompt: 'consent', visitor_id: req.query.visitor_id };

    const authorizationUrl = await idpartnerClient.getAuthorizationUrl(req.query, proofs, scope, extraAuthorizationParams);


  } catch (error) {




// Endpoint to get the trusted claims from the bank and create the Stytch user using them.

app.get('/oauth/callback', async (req, res, next) => {

  try {

    // Get user info (bank claims) from the bank.

    const token = await idpartnerClient.token(req.url, req.session.issuer, req.session.proofs);

    const bankClaims = await idpartnerClient.userInfo(req.session.issuer, token);

    // Create Stytch user using the trusted claims returned by the bank

    await stytchClient.users.create({


      name: {

        first_name: bankClaims.given_name,

        last_name: bankClaims.family_name


      trusted_metadata: {

        external_source: 'IDPartner'



    res.render('success', { data: bankClaims });

  } catch (error) {

    return next(error);



// Start the server

app.listen(port, config.ip, () => {

  console.log(`App listening on port ${port}`)