aeat.adapters.outbound.aeat.auth._clave_movil module¶
Cl@ve Móvil auth provider for AEAT Sede Electrónica.
Implements the AuthProvider protocol for the human-in-the-loop
Cl@ve Móvil flow against the live portal. Captures the URL template,
form selectors, and polling endpoints needed to drive the AEAT QR page
to a successful login handshake.
The provider returns AeatSession and AeatLoginAssertion
records with Cl@ve-specific detail payloads. Fresh logins persist
ClaveMovilSessionMetadata next to encrypted Playwright storage state;
resume and diagnostic probes rebuild ClaveMovilSessionDetail from that
metadata without carrying credential material in the session record.
Design summary:
Cl@ve Móvil is a human-in-the-loop flow. The provider observes only AEAT browser state; it cannot know whether the Cl@ve app displayed, accepted, rejected, or failed to receive a request unless the operator reports that separately.
The provider opens a headed Playwright window on fresh login so the operator can scan the QR visually. Resume-from-storage-state runs headlessly because no human interaction is required.
The persisted session stores Playwright state and provider metadata together in the encrypted session object. Kind-namespaced logical storage keys keep the Cl@ve and certificate sessions separate. Each persisted object is tagged with
SensitivityClassSESSION so the storage substrate applies the correct at-rest treatment.
See also
ClaveMovilSessionMetadata for the encrypted persistence contract,
ClaveMovilSessionDetail for the public session payload, and
ClaveMovilApprovalTimeoutError for operator-reportable live-flow
failures.
- class ClaveMovilAuthProvider(settings, *, browser_session_factory=None, navigation_timeout_ms=30000)[source]¶
Bases:
_ClaveMovilPageFlowMixinCl@ve Móvil implementation of the
AuthProviderprotocol.Constructed by
adapters.outbound.aeat.auth.select_provider()whenkind == AuthProviderKind.CLAVE_MOVIL. Fresh login can run the configured non-QR confirmation flow or the alternate QR flow; resume runs headlessly because the stored cookies are sufficient.The provider owns the lifecycle contract;
_ClaveMovilPageFlowMixinsupplies page-driving helpers and this class turns those browser outcomes intoAeatSession,AeatLoginAssertion, andAuthProviderDescriptionrecords.- Parameters:
settings (Settings)
browser_session_factory (BrowserSessionFactory | None)
navigation_timeout_ms (int)
- kind: AuthProviderKind¶
- async authenticate(*, browser_session=None, target_url=None)[source]¶
Run the Cl@ve Móvil login flow and return an
AeatSession.Attempts to resume a cached session first. Falls back to the human-in-the-loop QR-scan flow (or the non-QR DNI/NIE + contraste fallback, when
AEAT_CLAVE_PREFER_NON_QR=true). Fresh success writesClaveMovilSessionMetadataand returns a session whose provider detail isClaveMovilSessionDetail.- Return type:
- Parameters:
browser_session (BrowserSessionLike | None)
target_url (str | None)
- async probe_persisted_session(*, browser_session=None, target_url=None)[source]¶
Probe the encrypted persisted session without side effects.
Unlike
authenticate(), this method NEVER falls back to a fresh login and NEVER deletes the persisted session, even when the probe fails. Callers can therefore use it as a pure diagnostic without accidentally triggering a fresh operator-mediated Cl@ve request. A successful probe refreshes the stored idle deadline using the returnedAeatLoginAssertiontimestamp.- Return type:
- Returns:
A 2-tuple of (
AeatSession,AeatLoginAssertion).- Parameters:
browser_session (BrowserSessionLike | None)
target_url (str | None)
- async verify(session, *, target_url=None)[source]¶
Re-probe that
session’s cookies still unlock a Sede page.Explicit
target_urlprobes go through AEAT’s selector dispatcher, because some Cl@ve-backed apps only establish target-local state when dispatched from the selector. When no explicit target is supplied and the session metadata has a concrete post-auth landing URL, the probe can navigate there directly.The returned
AeatLoginAssertioncarriesClaveMovilLoginAssertionDetail, including the observed landing URL and whether the probe reached an authenticated AEAT page.- Return type:
- Returns:
An
AeatLoginAssertiondescribing the probe outcome.- Parameters:
session (AeatSession)
target_url (str | None)
- describe()[source]¶
Return an
AuthProviderDescriptionfor the Cl@ve Móvil provider state.Severity is set explicitly here so a normal pending state — Cl@ve Móvil completion requires an operator-mediated tap on the phone — is paired with
info, never the loudesterrortoken (round-5 M5). A malformed identity is a real configuration fault and surfaces aswarning; the no-identity case is an undeclared state and surfaces asinfo. Identity validation is delegated toclassify_identity(), which raisesClaveMovilConfigurationErrorfor unsupported DNI/NIE shapes.- Return type:
- async close()[source]¶
Tear down any retained
BrowserContextLikeand browser session.- Return type: