npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

lib-fints

v1.0.2

Published

Typescript/Javascript client library for Online-Banking via the FinTS 3.0 protocol with PIN/TAN

Downloads

498

Readme

Lib-FinTS

A Typescript/Javascript client library for Online-Banking via the FinTS 3.0 protocol with PIN/TAN. The library has no dependencies on other libraries

Getting Started

These instructions will show you how to install the library on your local machine and give a quick sample of how to use the library

Prerequisites

Product Registration

In order to communicate with banks via the FinTS protocol you have to register a product ID with the german banking industry (Deutsche Kreditwirtschaft) which you need to pass as part of the configuration to the client:

In order to fulfill the PSD2 requirements regarding transparency about the software used by customers, the German Banking Industry has established a process for registering FinTS products in order to be able to provide customers with information regarding FinTS usage. FinTS product registration is currently offered free of charge by the German Banking Industry.

ZKA Registration Website

Runtime Environment

The library is written in Typescript and compiled to the ES2022 Javascript language standard which means a minimum Node version of 18 is required.

A note about Browsers: It wouldn't be hard to make the code compatible with a browser environment, but communicating directly from the front-end with a bank server will most likely fail because of the imposed CORS restrictions from web browsers and the lack of corresponding CORS headers in bank server responses.

Installing

Installation is straight forward by simply adding the npm package. The package has no further dependencies on other packages.

npm i lib-fints

Sample Usage

The main public API of this library is the FinTSClient class and FinTSConfig class. In order to instantiate the client you need to provide a configration instance. There are basically two ways to initialize a configuration object, one is when you communicate with a bank for the first time and the other when you already have banking information from a prevous session available (more on that later).

If you don't have any previous banking information available you can use the static forFirstTimeUse() factory method like this:

const config = FinTSConfig.forFirstTimeUse(productId, productVersion, bankUrl, bankId, userId, pin);

const client = new FinTSClient(config);

Then you should first make a synchronization call to get banking and account information:

let syncResponse = await client.synchronize();

you should always check the success and requiresTan properties of any response object because other data might only be available when success=true and requiresTan=false. in any case you can also check the bankAnswers array for return messages from the bank which may contain the reasons for a failed request.

If the call is successfull the response will contain a bankingInformation object filled with all the relevant information provided by the bank from synchronization:

export type BankingInformation = {
  systemId: string;
  bpd?: BPD;
  upd?: UPD;
  bankMessages: BankMessage[];
};

The BPD object (BankParameterDaten) contains general information (e.g. available TAN methods and allowed transactions) and the UPD object (UserParameterDaten) user-specific information which is mainly the list of the user's bank accounts.

Unfortunately with this first synchronization call most banks will most likely only return most of the BPA information but no UPD (accounts) information, which is needed to fetch balances or statements. The reason for this is that you need to specify a TAN method before making the synchronization call, but how would you know which TAN methods are available and how to specify them? This is why you need to make a second synchronization call with a TAN method selected from the availableTanMethodIdsin the BPA, returned from the first synchronization call:

// for simplicity, we just select the first available TAN method
client.selectTanMethod(syncResponse.bankingInformation.BPD.availableTanMethodIds[0]);

now you can repeat the syncronization call from above and it will return additional data including the UPD with the account information.

Finally you can start fetching balances or statements:

// for simplicity, use the first account
const account = syncResponse.bankingInformation.upd.bankAccounts[0];

// fetch the current balance
const balanceResponse = await client.getAccountBalance(account.accountNumber);

// fetch all available statements
const statementResponse = await client.getAccountStatements(account.accountNumber);

These are only the most basic steps needed to retrieve information from the bank. It kept many questions unanswered like "how to handle TANs" or "how to avoid synchronizations every time you start a new session". These are explained in the corresponding sections below.

More detailed API Description

Handle TAN challenges from the bank

Most transactions may require authorization with a two step TAN process. As mentioned above in the sample, every response may set the requiresTanproperty to true which means that the response does not include the expected transaction data, but some additional TAN related properties. You first need to handle this TAN challenge by asking the user for the TAN and sending it back to the bank to continue the process and retrieve the actual transaction result:

// we use the node readline interface later to ask the user for a TAN
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

let response = await client.getAccountStatements(account.accountNumber);

if (!response.success) {
  return;
}

// need to check if a TAN is required to continue the transaction
if (response.requiresTan) {
  // asking the user for the TAN, using the tanChallenge property
  const tan = await rl.question(response.tanChallenge + ': ');
  // continue the transaction by providing the tanReference from the response and the entered TAN
  response = await client.getAccountStatementsWithTan(response.tanReference!, tan);
}

The FinTSClientcontains for every transaction method like synchronize() or getAccountStatements() a corresponding ...WithTan() method which needs to be called to continue the transaction with the given tanReference returned in the first response. The response object of this second call should now contain all transaction related data, assuming success=true.

Starting a session from saved banking information

As mentioned earlier there is a second way to initialize the FinTSClient with a FinTSConfig when you already performed a synchronization in a previous session and this is by providing the bankingInformation object received from previous uses. This bankingInformation object, which contains the general bank (BPD) and accounts information (UPD), should be persisted after a session and reloaded in the next session. This not only saves you from making the same synchronization requests every time before making a transaction, but the sychronization will also assign a systemId (a property in bankingInformation) to your client which should stay the same once assigned.

const config = FinTSConfig.fromBankingInformation(
  productId,
  productVersion,
  bankingInformation,
  userId,
  pin,
  tanMethodId,
  tanMediaName // when also needed (see below)
);
const client = new FinTSClient(config);

You should also set the TAN method to use, by using the optional tanMethodId and tanMediaName parameters or calling client.selectTanMethod() before making the first transaction.

Tan Media

It might be the case that you have more than one active TAN media available (like multiple mobile phones) and the bank requires you to also specify which TAN media to use. You can find out if this is the case by inspecting the TanMethod object in the BPD. You can get a list of all available TAN methods from the config.availableTanMethods property or if you already selected a TAN method with config.selectedTanMethod.

export type TanMethod = {
  id: number;
  name: string;
  version: number;
  activeTanMediaCount: number;
  activeTanMedia: string[];
  tanMediaRequirement: TanMediaRequirement;
};

The TanMethod object contains a property tanMediaRequirement and if this is set to TanMediaRequirement.Required, you also need to select a TAN media, either by providing the name in the configuration factory method FinTSConfig.fromBankingInformation() or by using client.selectTanMedia().

The property activeTanMedia contains a list of the TAN media names you can use for selection.

Banking Information may be updated any time

The bankingInformation is primarily obtained by the synchronize() calls as seen above. But what if the banking information changed since the last synchronization call and how would you know? For this reason the BPD and UPD are versioned and with every transaction made, not just synchronizations, the currently used versions are provided to the bank and if something changed, the bank will sent back new versions of the BPD and UPD respectively. This is all handled by the client but you need to check the bankingInformationUpdated property, which is available in every response, which tells you if there were changes and make sure to persist the new version for future sessions. You can always get the up-to-date version of the bankingInformation object with config.bankingInformation.

Debugging

If you need to debug issues and the response.bankAnswers don't provide enough information, you can enable debugging of messages with:

config.debugEnabled = true;

This will print out all sent messages and received responses to the console in a structured format.

Limitations

  • Only FinTS 3.0 is supported (older versions may not work)
  • Only PIN/TAN security is supported
  • Currently only the following transactions are supported:
    • Synchronize bank and account information
    • Fetching account balances
    • Fetching account statements

Implementing further transactions should be straight forward and contributions are highly appreciated

Successfully tested with the following banks

  • DKB
  • ING-DiBa
  • Renault Bank Direkt

Built With

Contributing

Feel free to create an issue if you want to report a bug.

If you tested this library with some other bank it would be great to hear from you and update the information on this page

As this is a free-time project, a lot of things are still remaining which could be added to this library, especially other kinds of transactions. If you want to contribute with pull-requests this would be highly appreciated

License

This project is licensed under the LGPL 3.0 License - see the LICENSE file for details

References