Many operations in FinTS will require a form of two-step authentication, called TANs. TANs are mostly required for operations that move money or change details of a bank account. TANs can be generated with a multidue of methods, including paper lists, smartcard readers, SMS messages, and smartphone apps.
Before doing any operations involving TANs, you should get a list of supported TAN mechanisms:
mechanisms = client.get_tan_mechanisms()The returned dictionary maps identifiers (generally: three-digit numerals) to instances of a :func:`~fints.formals.TwoStepParametersCommon` subclass with varying fields, depending on the version of the two-step process and the bank.
The name field of these objects provides a user-friendly name of the TAN mechanism that you can display to the user to choose from. To select a TAN mechanism, you can use :func:`~fints.client.FinTS3PinTanClient.set_tan_mechanism`, which takes the identifier used as key in the :func:`~fints.client.FinTS3PinTanClient.get_tan_mechanisms` return value.
If the description_required attribute for the TAN mechanism is :attr:`~fints.formals.DescriptionRequired.MUST`,
you will need to get a list of TAN media with :func:`~fints.client.FinTS3PinTanClient.get_tan_media` and select the
appropriate one with :func:`~fints.client.FinTS3PinTanClient.set_tan_medium`.
You may not change the active TAN mechanism or TAN medium within a standing dialog (see :ref:`client-dialog-state`).
The selection of the active TAN mechanism/medium is stored with the persistent client data (see :ref:`client-state`).
.. autoclass:: fints.client.FinTS3PinTanClient :members: get_tan_mechanisms, set_tan_mechanism, get_current_tan_mechanism, get_tan_media, set_tan_medium :noindex: :undoc-members:
When you try to perform an operation that requires a TAN to proceed, you will receive an object containing the bank's challenge (and some internal data to continue the operation once the TAN has been processed):
.. autoclass:: fints.client.NeedTANResponse :undoc-members: :members:
The challenge attribute will contain human-readable instructions on how to proceed.
The challenge_html attribute will possibly contain a nicer, formatted, HTML version of the challenge text
that you should prefer if your primary interface can render HTML. The contents are guaranteed to be proper and
clean (by using the bleach library): They can be used with mark_safe in Django.
The challenge_hhduc attribute will contain the challenge to be used with a TAN generator device using the
Hand Held Device Unidirectional Coupling specification (such as a Flicker-Code).
If you want to use chipTAN with an optical TAN device, we provide utilities to print the flicker code on
a unix terminal. Just pass the challenge_hhd_uc value to this method:
.. autofunction:: fints.hhd.flicker.terminal_flicker_unix
You should probably catch for KeyboardInterrupts to allow the user to abort the displaying and to continue
with the TAN:
try:
terminal_flicker_unix(result.challenge_hhd_uc)
except KeyboardInterrupt:
passOnce obtained the TAN, you can send it with the send_tan client method:
.. autoclass:: fints.client.FinTS3PinTanClient :members: send_tan :noindex:
For example:
tan = input('Please enter the TAN code: ')
result = client.send_tan(result, tan)The :func:`~fints.client.NeedTANResponse.get_data` method and :func:`~fints.client.NeedRetryResponse.from_data` factory method can be used to store and restore a TAN state object between steps.
.. autoclass:: fints.client.NeedRetryResponse :undoc-members: :members: from_data
You SHOULD use this facility together with the client and dialog state restoration facilities:
client = FinTS3PinTanClient(...)
# Optionally: choose a tan mechanism with
# client.set_tan_mechanism(…)
with client:
response = client.sepa_transfer(...)
dialog_data = client.pause_dialog()
client_data = client.deconstruct()
tan_data = response.get_data() tan_request = NeedRetryResponse.from_data(tan_data)
print("TAN request: {}".format(tan_request.challenge))
tan = input('Enter TAN: ') tan_request = NeedRetryResponse.from_data(tan_data)
client = FinTS3PinTanClient(..., from_data=client_data)
with client.resume_dialog(dialog_data):
response = client.send_tan(tan_request, tan)
print(response.status)
print(response.responses).. autoclass:: fints.formals.TwoStepParameters2 :noindex: :undoc-members: :members: :inherited-members: :member-order: bysource :exclude-members: is_unset, naive_parse, print_nested
.. autoclass:: fints.formals.TwoStepParameters3 :noindex: :undoc-members: :members: :inherited-members: :member-order: bysource :exclude-members: is_unset, naive_parse, print_nested
.. autoclass:: fints.formals.TwoStepParameters5 :noindex: :undoc-members: :members: :inherited-members: :member-order: bysource :exclude-members: is_unset, naive_parse, print_nested