akahu
    TypeScript icon, indicating that this package has built-in type declarations

    1.1.0 • Public • Published

    Akahu Javascript SDK

    Akahu is New Zealand’s open finance platform.

    Akahu builds and maintains data integrations with banks and other financial institutions. We bundle those integrations into a simple API for developers.

    This SDK provides utilities for both node.js and client applications to simplify and enhance the usage of Akahu APIs.

    Table of contents

    Access to Akahu

    Before you can get started using Akahu APIs, you will first need to register your application with Akahu. If you do not yet have an application registered with Akahu, use the Contact Us form to get in touch.

    Once you have registered your Akahu application, you will be issued with the following:

    • Your Akahu App ID Token
    • Your Akahu App Secret

    You will need to use these credentials when interacting with Akahu API endpoints.

    Important: It is extremely important that you keep your App Secret secure. This means that it must not be used in client applications, which may expose the secret in their source code. Akahu API endpoints that require the use of your App Secret for authentication must only be accessed from server applications.

    Installation

    Using npm:

    npm install akahu
    

    Using yarn:

    yarn add akahu
    

    Usage

    As an ES Module:

    import { AkahuClient } from 'akahu';

    As a CommonJS module:

    const { AkahuClient } = require('akahu');

    Fetching user and account data:

    // Replace appToken with your App Token
    const appToken = 'app_token_...';
    
    // Replace with an OAuth user access token. See note below for details.
    const userToken = 'user_token_...';
    
    // Create an instance of the AkahuClient and fetch some information
    const akahu = new AkahuClient({ appToken });
    const user = await akahu.users.get(userToken);
    const accounts = await akahu.accounts.list(userToken);
    
    // Let's have a look at what we got back
    console.log(`${user.email} has linked ${accounts.length} accounts:`);
    
    for (const account of accounts) {
      const { connection, name, formatted_account, balance } = account;
    
      console.log(`  ${connection.name} account "${name}" (${formatted_account}) ` +
                  `with available balance $${balance.available}.`);
    }
    
    // Example output:
    // user@example.com has linked 2 accounts:
    //   Westpac account "Westpac Choice" (01-0137-0000000-00) with available balance $447.75.
    //   Westpac account "Westpac eSaver" (01-0137-0000000-01) with available balance $17019.34.

    Note: If you are trialling Akahu using a Personal App, you will be able to find your App Token and User Token at https://my.akahu.io/developers. Otherwise, the user token must first be obtained by completing the OAuth2 authorization flow.

    Reference

    Examples

    OAuth2 authorization

    Akahu uses the OAuth2 authorization flow to allow your application to request authorization from users to access Akahu APIs on their behalf. This authorization flow consists of the following steps:

    1. Your application directs the user to the Akahu authorization page.
    2. The user logs in to Akahu and chooses which accounts they wish to authorize your application to access.
    3. The user is redirected back to your application along with a short-lived authorization code included in the URL query parameters.
    4. Your application server exchanges this authorization code with Akahu for a longer-lived user access token, which you can then use to authorize API requests on their behalf.

    This SDK provides utilities to simplify integration of this authorization flow into your application.

    Generating the authorization url (client)

    The auth.buildAuthorizationUrl helper simplifies generating the link to direct the user to the Akahu authorization page. This helper can be run on either client or server.

    The below example demonstrates a simple React component that will link the user to the Akahu authorization page when clicked.

    import React from 'react';
    import { AkahuClient } from 'akahu';
    
    const akahu = new AkahuClient({
      // Configure your app token here.
      // App secret is not required and should not be included client-side.
      appToken: process.env.AKAHU_APP_TOKEN,
    });
    
    // Configure your redirect uri (for step 3) here
    const akahuOAuthRedirectUri = 'https://my.app.domain/auth/akahu';
    
    export default LoginWithAkahuLink = () => {
      const authUrl = akahu.auth.buildAuthorizationUrl({
        redirect_uri: akahuOAuthRedirectUri,
        email: '...',  // Optionally prefill the users email address
      });
    
      return <a href={authUrl}>Login with Akahu</a>;
    };

    Authorization code exchange (server)

    The authorization code exchange can be performed using the auth.exchange helper.

    The below example shows a basic Express.js endpoint to handle the OAuth redirect (step 3) and complete the auth code exchange (step 4) to retrieve a user access token.

    import express from 'express';
    import { AkahuClient } from 'akahu';
    
    const akahu = new AkahuClient({
      // Configure your app token here and secret here.
      // Both app token and secret are required to complete the auth code exchange
      appToken: process.env.AKAHU_APP_TOKEN,
      appSecret: process.env.AKAHU_APP_SECRET
    });
    
    const app = express();
    
    // The redirect URI that was included as a parameter in the authorization request
    // must also be included in the auth code exchange request to validate its authenticity.
    const akahuOAuthRedirectUri = 'https://my.app.domain/auth/akahu';
    
    app.get('/auth/akahu', async (req: express.Request, res: express.Response): void => {
      // Exchange the auth code - this is included as a query parameter in the request
      const tokenResponse =  await akahu.auth.exchange(req.query.code, akahuOAuthRedirectUri);
      const { access_token, expires_in } = tokenResponse;
    
      /*
      ...
      Save access_token (and optionally expires_in) against your application user in the database.
      ...
      */
    
      // Success! You can now use access_token to authorize Akahu API requests on behalf of the user.
      res.sendStatus(200);
    });

    Listing transactions

    The transactions.list method can be used to retrieve transactions from accounts that the user has authorized your application to access.

    Transaction responses are paginated (Akahu only returns small batches at a time), so we must page through them to get all of them.

    import { AkahuClient } from "akahu";
    // Optional type defs for Typescript
    import type { Transaction, TransactionQueryParams } from "akahu";
    
    const akahu = new AkahuClient({
      appToken: process.env.AKAHU_APP_TOKEN,
    });
    
    // Replace with an OAuth user access token
    const userToken = "user_token_...";
    
    // Specify a start and end timestamp to filter by a date range. If no date range
    // is provided, transactions from the last 30 days will be returned.
    const query: TransactionQueryParams = {
      // start: "2021-01-01T00:00:00.000Z",
      // end: "2021-01-02T00:00:00.000Z",
    };
    
    const transactions: Transaction[] = [];
    
    do {
      // Transactions are returned one page at a time
      const page = await akahu.transactions.list(userToken, query);
      // Store the returned transaction `items` from each page
      transactions.push(...page.items);
      // Update the cursor to point to the next page
      query.cursor = page.cursor.next;
      // Continue until the server returns a null cursor
    } while (query.cursor !== null);
    
    console.log(`Retrieved ${transactions.length} transactions:`);
    for (const transaction of transactions) {
      console.log(transaction.description);
    }

    Making a transfer

    The transfers.create method can be used to initiate a bank transfer between two of a users connected bank accounts:

    // Make a $5 transfer between these two accounts
    const transfer = await akahu.transfers.create(
      userToken,
      {
        from: "acc_1111111111111111111111111",
        to: "acc_2222222222222222222222222",
        amount: 5
      }
    );
    console.log("Transfer Initiated:", transfer._id);

    Receiving webhooks

    This example demonstrates a basic Express.js endpoint to receive and validate Akahu webhook events.

    This endpoint follows the recommended webhook verification process as documented at https://developers.akahu.nz/docs/reference-webhooks#verifying-a-webhook.

    By default, AkahuClient uses an internal in-memory cache to avoid downloading the webhook signing key each time a webhook is received. See caching webhook signing keys for more advanced caching options.

    For a complete reference of the different webhook payloads that your application may receive, see https://developers.akahu.nz/docs/reference-webhooks#what-a-webhook-looks-like.

    import express from "express";
    import { AkahuClient } from 'akahu';
    
    // Optional type defs for Typescript
    import type { WebhookPayload } from 'akahu';
    
    // IMPORTANT: initialize the client globally to make use of built in public key
    // caching. Initializing a new client per-request would cause the public key to
    // be downloaded from Akahu servers for every webhook that is received.
    const akahu = new AkahuClient({
      appToken: process.env.AKAHU_APP_TOKEN,
      appSecret: process.env.AKAHU_APP_SECRET
    });
    
    // Initialize the express app
    const app = express();
    
    // Use `express.raw({type: 'application/json'})` to get the raw request body.
    // The raw, unparsed body is required to validate the webhook signature.
    app.post('/akahu-webhook', express.raw({type: 'application/json'}), async (req, res) => {
    
      // This signature will be used to validate the authenticity of the webhook payload.
      const signature = req.headers['X-Akahu-Signature'];
    
      // This is the ID of the signing key that was used to generate the signature
      const keyId = req.headers['X-Akahu-Signing-Key']
    
      let payload: WebhookPayload;
    
      // The AkahuClient will lookup the public key that matches `keyId` and use this
      // key to validate the webhook signature.
      try {
        // If validation is successful, the JSON payload is deserialized and returned.
        payload = await akahu.webhooks.validateWebhook(keyId, signature, req.body);
      } catch (e) {
        console.log(`Webhook validation failed: ${e.message}`);
        return res.status(400).send(e.message);
      }
    
      // Do something with the webhook payload.
      const { webhook_type, webhook_code, ...params } = payload;
      console.log(`Received webhook type: '${webhook_type}', code: ${webhook_code}:`);
      console.log(params);
    
      // Return a 200 response to acknowledge receipt of the webhook
      res.sendStatus(200);
    });

    Caching webhook signing keys

    The previous example makes use of the in-memory caching of the webhook signing key by AkahuClient to avoid making excessive requests to the Akahu API. However, this caching may not be effective if your application is deployed as a stateless/ephemeral function (e.g. using AWS Lambda). In such cases, it is recommended to use an external cache such as redis or memcached to allow shared caching between invocations of your application.

    To make use of an external cache to store the webhook signing key, supply the optional cacheConfig config object to validateWebhook(). The cache attribute of this object must implement the WebhookSigningKeyCache interface to provide access to the external cache. See WebhookCacheConfig for the complete set of caching configuration that is available.

    The below example wraps an instance of the node-redis client get and set methods to provide this interface:

    import { promisify } from "util";
    import { createClient } from 'redis';
    
    const redis = createClient(/* ... */);
    
    const cacheConfig = {
      cache: {
        // Convert redis client methods to promise friendly implementations
        get: promisify(redis.get).bind(redis),
        set: promisify(redis.set).bind(redis),
      }
    };
    
    /* ... */
    
    try {
      payload = await akahu.webhooks.validateWebhook(keyId, signature, req.body, cacheConfig);
    } catch (e) {
      /* ... */
    }

    Resources

    Install

    npm i akahu

    DownloadsWeekly Downloads

    90

    Version

    1.1.0

    License

    ISC

    Unpacked Size

    263 kB

    Total Files

    32

    Last publish

    Collaborators

    • david.akahu
    • ben-akahu