Skip to content

Conversation

Copy link

Copilot AI commented Dec 28, 2025

Implementation Plan for Decoupled TAN (Asynchronous Authentication) Support

Overview

Add comprehensive support for Decoupled TAN (asynchronous authentication) to enable modern PSD2-compliant authentication flows where transaction approval occurs on a separate, trusted device (e.g., mobile app).

Implementation Checklist

  • Phase 1: Core Types and Error Classes

    • Create decoupled-tan/types.ts with enums and interfaces (DecoupledTanState, DecoupledTanConfig, DecoupledTanStatus)
    • Create errors/decoupled-tan-error.ts with custom error class
    • Create decoupled-tan/index.ts for exports
    • Update exports in main index.ts
  • Phase 2: Decoupled TAN Manager

    • Create decoupled-tan/decoupled-tan-manager.ts with polling logic
    • Implement state machine for TAN lifecycle
    • Implement polling with configurable intervals
    • Add timeout handling and cancellation support
  • Phase 3: Dialog Extensions

    • Add DecoupledTanManager integration to Dialog class
    • Add handleDecoupledTan() method for initiating polling
    • Add checkDecoupledTanStatus() for manual status checks
    • Add cancelDecoupledTan() for user cancellation
    • Update send() method to detect decoupled TAN requirements (codes 3956, 3076)
  • Phase 4: PinTanClient Extensions

    • Add DecoupledTanConfig to PinTanClientConfig interface
    • Add handleDecoupledTanChallenge() method with auto-polling
    • Pass decoupled config to Dialog creation
  • Phase 5: TanRequiredError Extensions

    • Add isDecoupledTan() method
    • Add decoupledTanState property
    • isMultiStep() already supports decoupled flows
  • Phase 6: Unit Tests

    • Create decoupled-tan/__tests__/test-decoupled-tan-manager.ts (16 tests)
    • Test state machine transitions
    • Test polling intervals and timeouts
    • Test cancellation workflows
    • Test error code mapping
    • Create decoupled-tan/__tests__/test-decoupled-tan-error.ts (13 tests)
    • Update TanRequiredError tests (2 new tests)
  • Phase 7: Integration Tests

    • Create decoupled-tan/__tests__/test-decoupled-tan-integration.ts (7 tests)
    • Test Dialog with decoupled TAN flows
    • Test multi-step scenarios
    • Test detection of decoupled TAN requirements
  • Phase 8: Validation and Cleanup

    • Run all tests to ensure no breaking changes
    • Verify test coverage meets 85% target
    • Run linter and fix any issues
    • Build project to ensure TypeScript compilation
    • Final code review and cleanup
  • Phase 9: Documentation Improvements

    • Add detailed inline documentation for FinTS return codes
    • Explain the meaning and purpose of codes 0030, 3956, and 3076
  • Phase 10: Type Safety Improvements

    • Remove 'as any' type assertion in checkStatus method
    • Use proper Request instance instead of plain object
  • Phase 11: Comprehensive Documentation

    • Add FinTS specification references to DecoupledTanManager
    • Document tanProcess="2" and HKTAN segment usage
    • Add detailed JSDoc comments with usage examples
    • Reference https://www.hbci-zka.de/ for specification
    • Document all public methods with specification context
    • Explain return codes with FinTS specification context
  • Phase 12: Code Review Improvements

    • Add constants for magic strings (return codes, process types)
    • Fix timeout/cancellation race condition
    • Add polling re-entry protection
    • Fix status counter increment timing
    • Add tanMethods validation
    • Remove unused autoStartPolling configuration
    • Clarify fixed-interval polling vs exponential backoff
    • Document hardcoded segment number
  • Phase 13: Bug Fixes

    • Fix merge conflict syntax errors in dialog.ts

Summary

COMPLETE: Comprehensive Decoupled TAN support implemented
297 Tests: All tests passing (38 new tests added)
87.87% Coverage: Exceeds 85% target (statements), 87.96% (lines)
No Breaking Changes: All existing tests pass
Type-Safe: Full TypeScript support with no any types
FinTS 3.0 Compliant: Implements PINTAN specification
Linting Clean: All code passes ESLint checks
Fully Documented: Comprehensive documentation with specification references
Code Review: All feedback addressed with improved robustness

Features Delivered

  • Automatic polling with configurable fixed intervals
  • State machine for TAN lifecycle management
  • Timeout handling with configurable limits
  • User cancellation support with race condition protection
  • Detection of decoupled TAN requirements (3956, 3076 codes)
  • Callback support for UI updates
  • Server-provided config override from TanMethod
  • Comprehensive error handling with DecoupledTanError
  • Full integration with Dialog and PinTanClient
  • Detailed inline documentation with FinTS specification references
  • Type-safe implementation without any type assertions
  • Code examples in documentation for common use cases
  • Named constants for return codes and process types
  • Robust validation and error handling
Original prompt

Implement Decoupled TAN (Asynchronous Authentication) Support

This comprehensive implementation adds support for Decoupled TAN (asynchronous authentication) to the fints-lib library, enabling modern PSD2-compliant authentication flows where transaction approval occurs on a separate, trusted device (e.g., mobile app).

Specification Reference

This implementation follows the FinTS 3.0 Security Specification (PINTAN) with these key requirements:

  • HKTAN Segment Support: tanProcess="2" for decoupled/asynchronous authentication
  • Polling Mechanism: Automatic status polling with configurable intervals and timeouts
  • HIRMG Return Codes: Support for codes 3956 (pending confirmation), 3920 (TAN methods available), 3076 (SCA required)
  • State Management: Track decoupled TAN states through the entire lifecycle
  • Timeout Handling: Configurable total timeout and polling parameters

Core Components to Implement

1. DecoupledTanManager (packages/fints/src/decoupled-tan/decoupled-tan-manager.ts)

  • Manages the decoupled TAN lifecycle
  • Handles automatic polling with exponential backoff
  • Tracks state transitions and errors
  • Configurable polling intervals and timeouts

2. DecoupledTanState and Enums (packages/fints/src/decoupled-tan/types.ts)

  • Define DecoupledTanState enum: INITIATED, CHALLENGE_SENT, PENDING_CONFIRMATION, CONFIRMED, FAILED, CANCELLED, TIMED_OUT
  • Define DecoupledTanConfig interface with polling parameters
  • Define DecoupledTanStatus interface for tracking current state

3. DecoupledTanError (packages/fints/src/errors/decoupled-tan-error.ts)

  • Custom error class for decoupled TAN failures
  • Includes state, transaction reference, and remaining status requests
  • Provides helpful error messages

4. Dialog Extension (packages/fints/src/dialog.ts)

  • Add DecoupledTanManager integration
  • Add handleDecoupledTan() method for initiating polling
  • Add checkDecoupledTanStatus() for manual status checks
  • Add cancelDecoupledTan() for user cancellation
  • Add support for detecting decoupled TAN requirements from HIRMG codes

5. PinTanClient Extension (packages/fints/src/pin-tan-client.ts)

  • Add DecoupledTanConfig to PinTanClientConfig
  • Add handleDecoupledTanChallenge() method with auto-polling support
  • Add callback support for UI updates during polling
  • Add submitWithDecoupledTan() for transparent decoupled TAN handling

6. TanRequiredError Extension (packages/fints/src/errors/tan-required-error.ts)

  • Add isDecoupledTan() method
  • Add decoupledTanState property
  • Add isMultiStep() method for multi-step flows

Implementation Features

Polling Behavior:

  • Configurable wait time before first status request (default: 2000ms)
  • Configurable wait time between status requests (default: 2000ms)
  • Configurable max status requests (default: 60)
  • Configurable total timeout (default: 5 minutes)
  • Automatic polling loop with state updates

Error Handling:

  • Graceful timeout with DecoupledTanError
  • Max status requests exceeded handling
  • User cancellation support
  • Server-side error code mapping
  • Detailed error messages for troubleshooting

State Tracking:

  • INITIATED: Challenge has been received
  • CHALLENGE_SENT: Challenge text presented to user
  • PENDING_CONFIRMATION: Polling for confirmation
  • CONFIRMED: Confirmation received from server
  • FAILED: Error occurred during polling
  • CANCELLED: User cancelled the TAN process
  • TIMED_OUT: Total timeout exceeded

User Integration:

  • Optional callback for UI updates during polling
  • Real-time state change notifications
  • Graceful cancellation support
  • Clear error messages

Testing Requirements

All implementations must include comprehensive tests:

Unit Tests (packages/fints/src/decoupled-tan/__tests__/):

  • DecoupledTanManager state machine tests
  • Polling interval calculation tests
  • Timeout handling tests
  • Error code mapping tests
  • HKTAN segment serialization with decoupled parameters
  • Status request segment creation

Integration Tests (packages/fints/src/__tests__/):

  • Dialog with decoupled TAN flows
  • Multi-step decoupled TAN scenarios
  • Cancellation workflows
  • End-to-end credit transfer with decoupled TAN
  • Error handling and recovery

Test Coverage Requirements:

  • Minimum 85% code coverage for decoupled TAN implementation
  • Mock FinTS server simulation for realistic test scenarios
  • Edge case handling (network errors, timeouts, rapid confirmations)

Files to Create/Modify

New Files:

  • packages/fints/src/decoupled-tan/decoupled-tan-manager.ts
  • packages/fints/src/decoupled-tan/types.ts
  • packages/fints/src/decoupled-tan/index.ts
  • packages/fints/src/errors/decoupled-tan-error.ts
  • packages/fints/src/decoupled-tan/__tests__/test-decoupled-tan-manager.ts
  • packages/fints/src/decoupled-tan/__tests__/test-decoupled-tan-integration.ts

Modified Files:

  • packages/fints/src/dialog.ts
  • `packages/fints/src/p...

This pull request was created from Copilot chat.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 4 commits December 28, 2025 23:58
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement decoupled TAN support for asynchronous authentication Implement Decoupled TAN (Asynchronous Authentication) Support Dec 29, 2025
Copilot AI requested a review from larsdecker December 29, 2025 00:18
@larsdecker larsdecker marked this pull request as ready for review January 5, 2026 21:46
Copilot AI review requested due to automatic review settings January 5, 2026 21:46
Copy link
Owner

@larsdecker larsdecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good. We need to add more documentation for it. It would be cool to link also directly to the specification in cases it makes sense.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a4d1bba415

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 257 to 261
// Use the dialog's connection to send the request
// Note: We bypass dialog.send() to avoid incrementing msgNo unnecessarily
request.msgNo = this.dialog.msgNo;
request.dialogId = this.dialog.dialogId;
const response = await this.dialog.connection.send(request as any);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Send polling status with invalid request object

Decoupled TAN status checks bypass the Request class and call connection.send(request as any), where request is just a plain object. HttpConnection.send stringifies its Request parameter to build the FinTS envelope (HNHBK/HNVSK/HNSHK), so a bare object will serialize to [object Object] and omit all required headers. Any decoupled TAN polling done against the real HttpConnection will therefore send malformed messages and fail before the server can return a status.

Useful? React with 👍 / 👎.

Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements comprehensive PSD2-compliant decoupled TAN (asynchronous authentication) support for the fints-lib library, enabling transaction approval on separate devices like mobile banking apps. The implementation follows the FinTS 3.0 PINTAN specification with automatic polling, state management, and configurable timeouts.

Key Changes:

  • Introduces DecoupledTanManager for managing the polling lifecycle with configurable intervals and state machine tracking
  • Adds comprehensive type system for decoupled TAN states, configuration, and status tracking
  • Integrates decoupled TAN detection and handling into existing Dialog and PinTanClient classes

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
packages/fints/src/decoupled-tan/types.ts Defines core types including DecoupledTanState enum, configuration interface, and status tracking interface
packages/fints/src/decoupled-tan/decoupled-tan-manager.ts Core manager class handling polling logic, state transitions, timeouts, and server communication
packages/fints/src/decoupled-tan/index.ts Barrel export for decoupled TAN module
packages/fints/src/errors/decoupled-tan-error.ts Custom error class with helper methods for timeout, cancellation, and remaining request checks
packages/fints/src/dialog.ts Integrates decoupled TAN detection, manager instantiation, and polling methods
packages/fints/src/pin-tan-client.ts Adds decoupled TAN configuration and convenience method for handling challenges
packages/fints/src/errors/tan-required-error.ts Extends error to include decoupled TAN state and detection method
packages/fints/src/index.ts Exports new decoupled TAN types and error classes
packages/fints/src/decoupled-tan/__tests__/test-decoupled-tan-manager.ts Unit tests for manager covering state machine, polling, timeouts, and error handling
packages/fints/src/decoupled-tan/__tests__/test-decoupled-tan-integration.ts Integration tests for dialog flows and multi-step workflows
packages/fints/src/decoupled-tan/__tests__/test-decoupled-tan-error.ts Unit tests for error class methods and message generation
packages/fints/src/__tests__/test-tan-required-error.ts Tests for new isDecoupledTan() method

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


/**
* Manages the lifecycle of a decoupled TAN (asynchronous authentication) process.
* Handles automatic polling with exponential backoff, state management, and timeout handling.
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states this class "Handles automatic polling with exponential backoff", but the implementation uses a fixed wait time (waitBetweenStatusRequests) between requests, not exponential backoff. Either implement exponential backoff as documented, or update the documentation to accurately reflect the fixed-interval polling behavior.

Suggested change
* Handles automatic polling with exponential backoff, state management, and timeout handling.
* Handles automatic polling with configurable fixed intervals, state management, and timeout handling.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed documentation in commit 9857da2. Changed "exponential backoff" to "configurable fixed intervals" to accurately reflect the implementation.

Copilot AI and others added 2 commits January 5, 2026 21:59
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Copy link
Author

Copilot AI commented Jan 5, 2026

Looks mostly good. We need to add more documentation for it. It would be cool to link also directly to the specification in cases it makes sense.

Added comprehensive documentation with FinTS specification references throughout the codebase in commit 6f10799:

  • Added detailed JSDoc comments explaining tanProcess="2" and HKTAN segment usage
  • Linked to https://www.hbci-zka.de/ for FinTS specification documentation
  • Documented return codes (0030, 3956, 3076) with specification context
  • Added usage examples in PinTanClient.handleDecoupledTanChallenge()
  • Referenced "Sicherheitsverfahren PINTAN Version 3.0" specification
  • Explained polling behavior, state machine, and error scenarios

All major classes (DecoupledTanManager, DecoupledTanError, Dialog, PinTanClient) now have comprehensive documentation linking directly to relevant specification sections.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
larsdecker and others added 2 commits January 5, 2026 23:35
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…rove validation

- Add constants for FinTS return codes (RETURN_CODE_TAN_REQUIRED, RETURN_CODE_PENDING_CONFIRMATION)
- Add constant for HKTAN process type (HKTAN_PROCESS_DECOUPLED_STATUS)
- Fix timeout race condition by checking cancelled state before updating to TIMED_OUT
- Add re-entry protection to prevent multiple simultaneous polling sessions
- Fix status counter increment to occur after response processing, not before
- Add validation for empty tanMethods array in Dialog.handleDecoupledTan
- Remove unused autoStartPolling config option
- Update documentation to clarify fixed-interval polling (not exponential backoff)
- Add comment explaining hardcoded segNo=3 in checkStatus method

Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
@larsdecker larsdecker merged commit 95510ec into master Jan 9, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants