-
Notifications
You must be signed in to change notification settings - Fork 0
Implement Decoupled TAN (Asynchronous Authentication) Support #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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>
larsdecker
left a comment
There was a problem hiding this 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.
There was a problem hiding this 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".
| // 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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>
There was a problem hiding this 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
DecoupledTanManagerfor 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. |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
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.
| * Handles automatic polling with exponential backoff, state management, and timeout handling. | |
| * Handles automatic polling with configurable fixed intervals, state management, and timeout handling. |
There was a problem hiding this comment.
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.
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Co-authored-by: larsdecker <1968186+larsdecker@users.noreply.github.com>
Added comprehensive documentation with FinTS specification references throughout the codebase in commit 6f10799:
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>
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>
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
decoupled-tan/types.tswith enums and interfaces (DecoupledTanState, DecoupledTanConfig, DecoupledTanStatus)errors/decoupled-tan-error.tswith custom error classdecoupled-tan/index.tsfor exportsindex.tsPhase 2: Decoupled TAN Manager
decoupled-tan/decoupled-tan-manager.tswith polling logicPhase 3: Dialog Extensions
handleDecoupledTan()method for initiating pollingcheckDecoupledTanStatus()for manual status checkscancelDecoupledTan()for user cancellationsend()method to detect decoupled TAN requirements (codes 3956, 3076)Phase 4: PinTanClient Extensions
handleDecoupledTanChallenge()method with auto-pollingPhase 5: TanRequiredError Extensions
isDecoupledTan()methoddecoupledTanStatepropertyisMultiStep()already supports decoupled flowsPhase 6: Unit Tests
decoupled-tan/__tests__/test-decoupled-tan-manager.ts(16 tests)decoupled-tan/__tests__/test-decoupled-tan-error.ts(13 tests)Phase 7: Integration Tests
decoupled-tan/__tests__/test-decoupled-tan-integration.ts(7 tests)Phase 8: Validation and Cleanup
Phase 9: Documentation Improvements
Phase 10: Type Safety Improvements
Phase 11: Comprehensive Documentation
Phase 12: Code Review Improvements
Phase 13: Bug Fixes
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
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:
Core Components to Implement
1. DecoupledTanManager (
packages/fints/src/decoupled-tan/decoupled-tan-manager.ts)2. DecoupledTanState and Enums (
packages/fints/src/decoupled-tan/types.ts)3. DecoupledTanError (
packages/fints/src/errors/decoupled-tan-error.ts)4. Dialog Extension (
packages/fints/src/dialog.ts)5. PinTanClient Extension (
packages/fints/src/pin-tan-client.ts)6. TanRequiredError Extension (
packages/fints/src/errors/tan-required-error.ts)Implementation Features
Polling Behavior:
Error Handling:
State Tracking:
User Integration:
Testing Requirements
All implementations must include comprehensive tests:
Unit Tests (
packages/fints/src/decoupled-tan/__tests__/):Integration Tests (
packages/fints/src/__tests__/):Test Coverage Requirements:
Files to Create/Modify
New Files:
packages/fints/src/decoupled-tan/decoupled-tan-manager.tspackages/fints/src/decoupled-tan/types.tspackages/fints/src/decoupled-tan/index.tspackages/fints/src/errors/decoupled-tan-error.tspackages/fints/src/decoupled-tan/__tests__/test-decoupled-tan-manager.tspackages/fints/src/decoupled-tan/__tests__/test-decoupled-tan-integration.tsModified Files:
packages/fints/src/dialog.tsThis 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.