
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
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.
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:
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.
Using npm:
npm install akahu
Using yarn:
yarn add akahu
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.nz/developers. Otherwise, the user token must first be obtained by completing the OAuth2 authorization flow.
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:
This SDK provides utilities to simplify integration of this authorization flow into your application.
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>;
};
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 } = tokenResponse;
/*
...
Save access_token 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);
});
🧹 Best Practice
To ensure that your application does not retain unnecessary access to user data, revoke access tokens in the event that they are no longer required (e.g. the user deletes their account).
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);
}
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);
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);
});
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) {
/* ... */
}
Added type definition for payment_consents.
Updated Axios dependency.
Added redirect_mode parameter to buildAuthorizationUrl (docs).
Added typings for Official Open Banking Migration.
Added typings for new API fields.
Added typings for new API fields.
This release updates the axios dependency to v1.8.3.
We don't expect that this will be a breaking change for most, however we have incremented the major version because the commonly used axios-fetch-adapter library is incompatible with this version of Axios. If your app is deployed on Cloudflare workers, you can now use the built-in fetch adapter by passing adapter: "fetch" when initialising the AkahuClient.
FAQs
Javascript SDK for Akahu
The npm package akahu receives a total of 1,272 weekly downloads. As such, akahu popularity was classified as popular.
We found that akahu demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.