Skip to content

Exempting Authentication Providers from TFA

TFA and Authentication Providers

Drupal Core uses services tagged with authentication_provider to authenticate incoming requests via AuthenticationSubscriber.

TFA enforces two-factor authentication on these providers through a combination of container compilation and event subscriber validation: - Interactive authentication methods (like standard web logins) are protected via user.auth decoration and session tracking. - Non-interactive or machine-to-machine authentication methods (such as API keys, OAuth2, or external SSO) that do not use user.auth or establish a standard cookie session will be rejected by TfaUserSetSubscriber unless explicitly exempted.

Reasons to Exempt an Authentication Provider

Exempting an authentication provider is typically required when: * Machine-to-Machine (M2M) APIs: Automated tooling, CI/CD pipelines, or third-party webhooks authenticate using API keys, bearer tokens, or JWTs where interactive 2FA challenge prompts cannot be rendered. * Third-Party Identity Providers (SSO): External SSO solutions (e.g., SAML, OpenID Connect) where multi-factor authentication is already enforced at the enterprise Identity Provider level.

Configuring Exempt Providers

Security Responsibility

Exempting an authentication provider allows requests authenticated by that provider to establish a user session or context without TFA being enforced by Drupal. Ensure that compensating controls (such as token rotation, IP allowlisting, or IdP-level MFA) are in place.

To exempt an authentication provider, define the tfa.auth_provider_bypass container parameter in your services.yml (e.g., sites/default/services.yml or local.services.yml):

services.yml
parameters:
  tfa.auth_provider_bypass:
    - 'oauth2_token'
    - 'api_key_auth'

You can also adjust the decoration priority if necessary (default is 50):

services.yml
parameters:
  tfa.auth_provider_bypass_priority: 50

How Provider Exemption Works Internally

During container compilation, TfaAuthDecoratorCompiler: 1. Scans all services tagged with authentication_provider. 2. Identifies services whose provider_id matches an entry in tfa.auth_provider_bypass. 3. Wraps the matching provider service in either TfaAuthDecorator or TfaChallengeAuthDecorator. 4. When the exempted provider successfully authenticates a request, its decorator sets a tfa_auth_method_bypass_approved flag in cache.tfa_memcache for the authenticated UID. 5. When AccountEvents::SET_USER fires, TfaUserSetSubscriber reads the memory cache flag, allows the user context to be set, and immediately deletes the flag to ensure single-request scoping.

Technical Constraints & Limitations

1. Mandatory Non-Exemptable Providers

The following core providers cannot be exempted and are explicitly rejected if placed in tfa.auth_provider_bypass: * cookie: Governs standard session authentication; must follow TFA's session validation flow. * http_basic: Directly delegates to user.auth, which enforces TFA token verification.

2. Supported Interface Combinations

TfaAuthDecoratorCompiler dynamically generates decorators for services implementing: - \Drupal\Core\Authentication\AuthenticationProviderInterface - \Drupal\Core\Authentication\AuthenticationProviderChallengeInterface

Providers implementing additional interfaces (such as \Drupal\Core\Authentication\AuthenticationProviderFilterInterface) are not automatically decorated by the compiler pass. For such providers, a custom decorator or custom event subscriber must be implemented to manage the authentication lifecycle.