Interface IUserAuthenticationSecondFactor
- All Known Subinterfaces:
IUserAuthenticationUI
IUserAuthenticationUI for it (SignIn L-6; the SignIn flow design, sections 3.5, 5 and 7): the sign-in policy of the application, the sign-in that waits for its second factor, the verification codes of an authenticator app (TOTP, RFC 6238), the recovery codes that stand in for a lost app, and the devices that are trusted not to be asked again - which are the devices of IUserAuthenticationUI.getSignedInDevices(IClientSessionGyro): the trust is kept with the device's token (CC-SIGNIN-MERGE-L5-L6-L8).The sign-in that waits. When a second factor is due - the account has one, or the policy requires one - the first factor signs nobody in: IUserAuthenticationUI.performInternalLogin(IClientSessionGyro, String, String) answers SigninResult.SUCCESS_SECOND_FACTOR_REQUIRED, records nothing in the session, and the server holds the user for this session, for 5 minutes. getSignInMethods(IClientSessionGyro) then tells what the user has. verifySecondFactor(IClientSessionGyro, String, String, int) completes the sign-in with a code, or with a passkey of the user in place of one (CC-LOGIN-PASSKEY-SECOND-FACTOR); when the policy requires a second factor of a user who has none, beginTotpEnrolment(IClientSessionGyro) and confirmTotpEnrolment(IClientSessionGyro, String) do. cancelPendingSignIn(IClientSessionGyro) ends it. While the sign-in waits the session has no user: every other call of IUserAuthenticationUI sees the session it saw before the first factor. Where the policy requires a passkey on the client and the user has none, the second factor does not complete the sign-in: it waits on, for the registration of a passkey (SigninResult.SUCCESS_PASSKEY_ENROLMENT_REQUIRED, IUserAuthenticationPasskeys).
The enrolment. beginTotpEnrolment(IClientSessionGyro) answers with the QR code and the setup key; nothing is saved until confirmTotpEnrolment(IClientSessionGyro, String) has the first code the app shows, so an app that was never enrolled correctly locks nobody out. The confirmation answers with the recovery codes, which are shown once. A user who is signed in changes how the user signs in - enrols, removes, gets new recovery codes - only after a recent sign-in: the one recent sign-in of the interface (IUserAuthenticationPasskeys.isRecentlyAuthenticated(IClientSessionGyro), 5 minutes), which the password (IUserAuthenticationPasskeys.reauthenticate(IClientSessionGyro, String)) and a passkey confirm; otherwise the answer is SigninResult.RECENT_SIGNIN_REQUIRED. The removal and new recovery codes need more: a session that verified a second factor - with a code when it signed in, or with a passkey, which is accepted with user verification only and is the proof of a second factor whether it signed the user in or confirmed the user (IUserAuthenticationPasskeys.finishPasskeyAssertion(IClientSessionGyro, String)). A session that was asked for none - the one of a trusted device, of a device that stays signed in - is answered SigninResult.SECOND_FACTOR_REQUIRED, however often the password confirms it: the user confirms with a passkey, or signs in with the second step.
A code is accepted once. Invalid codes are limited per account, per client source and per waiting sign-in. No method of this interface logs or returns a secret, a code or a recovery code, but for the two that hand the user the setup key and the recovery codes, once.
- Author:
- Christopher Mindus
Method Summary
Modifier and TypeMethodDescriptionbeginTotpEnrolment(IClientSessionGyro clientGyro) Begins the enrolment of an authenticator app: for the user whose sign-in waits in this session, otherwise for the user this session has signed in, after a recent sign-in.voidcancelPendingSignIn(IClientSessionGyro clientGyro) Ends the sign-in that waits in this session, whatever it waits for - its second factor, its passkey, the enrolment of either - and the enrolment that waits: the user goes back to the start.String[]confirmTotpEnrolment(IClientSessionGyro clientGyro, String code) Confirms the enrolment this session began, with the first code the authenticator app shows.default String[]enrolPasskeySecondFactor(IClientSessionGyro clientGyro) Makes a passkey the second factor of the user (CC-FIX-SIGNIN-2FA-CHOICE): the user chose a passkey on the choice of a second factor, and this session has registered one for the user a short time ago (IUserAuthenticationPasskeys.finishPasskeyRegistration(IClientSessionGyro, String, String)) - for the user whose sign-in waits for the enrolment of a second factor, or for the user it has signed in, after a recent sign-in.default intgetCodeClockOffset(IClientSessionGyro clientGyro) Gets the drift of a clock the last refused verification code of this session would have been right for (CC-FIX-SIGNIN-TOTP-ENROL, item 9): afterverifySecondFactor(IClientSessionGyro, String, String, int)orconfirmTotpEnrolment(IClientSessionGyro, String)answeredINVALID_CODEfor a code that matches a time step outside the verifier's window but within 5 minutes of this server's clock.getSecondFactorProof(IClientSessionGyro clientGyro) Gets the proof that this session's sign-in verified a second factor: the MFA proof of HUB-DESIGN 7.4 (ruling RB-11), which a session transfer carries.getSignInMethods(IClientSessionGyro clientGyro) Gets the ways the user signs in: of the user whose sign-in waits in this session, otherwise of the user this session has signed in.getSignInPolicy(IClientSessionGyro clientGyro) Gets the sign-in policy of the application of this session: the settings of the server environment with what the application overrides, and with the methods of a second factor narrowed to the ones this server can do.String[]regenerateRecoveryCodes(IClientSessionGyro clientGyro) Replaces the recovery codes of the user this session has signed in: every code made before is dead, used or not.removeSecondFactor(IClientSessionGyro clientGyro, String method) Removes a second factor of the user this session has signed in: for the authenticator app the secret, every recovery code and the trust of every device.default TotpEnrolmentrestartTotpEnrolment(IClientSessionGyro clientGyro) Begins the enrolment of an authenticator app ANEW ("Start over" on the set-up page, CC-FIX-SIGNIN-TOTP-ENROL): the enrolment this session held is dropped, whateverbeginTotpEnrolment(IClientSessionGyro)showed before, and a new secret is made; the entry an authenticator app made of the old QR code is dead from now on.default booleansetPreferredSecondFactor(IClientSessionGyro clientGyro, String method) Sets the second factor a sign-in of the user this session has signed in asks for first ("Ask me first for", CC-FIX-SIGNIN-2FA-CHOICE):getSignInMethods(IClientSessionGyro)then lists it first.verifySecondFactor(IClientSessionGyro clientGyro, String method, String code, int trustDays) Completes the sign-in that waits in this session with its second factor: the code is verified, and the user is signed in and recorded in the session exactly asIUserAuthenticationUI.performInternalLogin(IClientSessionGyro, String, String)records a user without one.
Method Details
getSignInPolicy
Gets the sign-in policy of the application of this session: the settings of the server environment with what the application overrides, and with the methods of a second factor narrowed to the ones this server can do.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.- Returns:
- The policy, never null.
getSignInMethods
Gets the ways the user signs in: of the user whose sign-in waits in this session, otherwise of the user this session has signed in.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.- Returns:
- The methods,
SignInMethods.NONEwhen the session has neither.
verifySecondFactor
SigninResult verifySecondFactor(IClientSessionGyro clientGyro, String method, String code, int trustDays) Completes the sign-in that waits in this session with its second factor: the code is verified, and the user is signed in and recorded in the session exactly asIUserAuthenticationUI.performInternalLogin(IClientSessionGyro, String, String)records a user without one.A verification code is accepted once: the code of a time step that was accepted before, or of an earlier one, is refused. A recovery code is accepted once.
A passkey in place of a code (CC-LOGIN-PASSKEY-SECOND-FACTOR). A user who has a passkey answers with it:
getSignInMethods(IClientSessionGyro)then lists the methodSignInPolicy.METHOD_PASSKEY, the first,IUserAuthenticationPasskeys.startPasskeyAssertion(IClientSessionGyro, boolean)returns the options that name the passkeys of the user, and this method takes the answer of the client as its code. The passkey is accepted with user verification only, is the proof of a second factor of the session, of the methodpasskey, and trusts the device as a verification code does. One answer is looked at per sign-in that waits: a passkey that is refused ends it, and the user begins again with the first factor. A passkey that was registered through an account recovery is no second factor for 24 hours: it is not listed and not accepted.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this sign-in.method- The method the code is of,SignInPolicy.METHOD_TOTP,SignInPolicy.METHOD_RECOVERYorSignInPolicy.METHOD_PASSKEY.code- The code as typed; whitespace is ignored, and so are the dashes and the letter case of a recovery code. For a passkey, the JSON text of the client'sAuthenticationResponseJSON.trustDays- The days this device is not to be asked for the second factor again ("Do not ask again on this device"), zero for none; at most what the policy allows. A recovery code trusts no device. The trust is kept with the device's token (IUserAuthenticationUI.trustDeviceForMFA(IClientSessionGyro, boolean)), and ends at every change of the password.- Returns:
SUCCESSorSUCCESS_CHANGE_PASSWORDwhen the user is signed in;SUCCESS_PASSKEY_ENROLMENT_REQUIREDwhen the code was accepted and the sign-in waits on, for the registration of a passkey the policy requires;PENDING_EXPIREDwhen no sign-in waits (none was begun, 5 minutes have passed, or too many invalid codes or a refused passkey ended it);INVALID_CODE;INVALID_PASSKEYfor a passkey that is refused for any reason;PASSKEY_REQUEST_EXPIREDwhen there is no request ofstartPasskeyAssertionto answer - the sign-in waits on;TOO_MANY_CODESwhen the account waits after invalid codes;TOO_MANY_INVALID_LOGINS_RETRY_LATERwhen the client source is held back;SECOND_FACTOR_METHOD_NOT_ALLOWED;SECOND_FACTOR_NOT_ENROLLEDwhen the user has no second factor to verify (one is enrolled first); or a server, application or system result.- Throws:
NullPointerException- Ifmethodis null.
beginTotpEnrolment
Begins the enrolment of an authenticator app: for the user whose sign-in waits in this session, otherwise for the user this session has signed in, after a recent sign-in. Nothing is saved: the enrolment is held for this session untilconfirmTotpEnrolment(IClientSessionGyro, String)confirms it, for at most 10 minutes, and a sign-in that waits is kept waiting as long. A second call for the same user, while the enrolment waits, shows the SAME enrolment again - the same secret and QR code, waiting another 10 minutes - so that going back and forth on the set-up page mints no new secret silently (SIGNIN-TOTP-ENROL-RESTART-SILENT, CC-FIX-SIGNIN-TOTP-ENROL);restartTotpEnrolment(IClientSessionGyro)is the one way to a new secret.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.- Returns:
- What the user needs to enrol the app: the QR code, the link and the setup key.
- Throws:
UserException- WithRECENT_SIGNIN_REQUIREDwhen the session has signed its user in too long ago, or has none;SECOND_FACTOR_ALREADY_ENROLLED;SECOND_FACTOR_METHOD_NOT_ALLOWEDwhen the policy has no authenticator app or no second factor at all; the result of a client source that is held back; or a server, application or system result.
confirmTotpEnrolment
Confirms the enrolment this session began, with the first code the authenticator app shows. The secret is saved now, sealed with the server's own key, and the account has a second factor from this moment on. When the sign-in waited for this enrolment, the user is signed in and recorded in the session now - unless the sign-in waits on, for the registration of a passkey the policy requires (IUserAuthenticationUI.getPendingSignIn(IClientSessionGyro)tells so). The code that confirmed is spent. The trust of every device of the user for MFA ends: no device was trusted by a code of this second factor.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.code- The verification code the app shows; whitespace is ignored.- Returns:
- The recovery codes of the account, each good for one sign-in. They are returned here once and cannot be read again: only a hash of each is kept.
- Throws:
UserException- WithSECOND_FACTOR_NOT_ENROLLEDwhen no enrolment of this session waits;INVALID_CODE(the enrolment keeps waiting;getCodeClockOffset(IClientSessionGyro)then names the drift of a clock the code would have been right for, when there is one);TOO_MANY_CODESfor the fifth invalid code, which drops the enrolment - the user starts over (restartTotpEnrolment(IClientSessionGyro); CC-FIX-SIGNIN-TOTP-ENROL); the result of a client source that is held back; or a server, application or system result.
restartTotpEnrolment
Begins the enrolment of an authenticator app ANEW ("Start over" on the set-up page, CC-FIX-SIGNIN-TOTP-ENROL): the enrolment this session held is dropped, whateverbeginTotpEnrolment(IClientSessionGyro)showed before, and a new secret is made; the entry an authenticator app made of the old QR code is dead from now on. The rest - the user it is for, what is held and for how long, the refusals - asbeginTotpEnrolment(IClientSessionGyro).The default begins as
beginTotpEnrolment(IClientSessionGyro)does: an implementation that keeps no enrolment to show again has nothing to drop.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.- Returns:
- What the user needs to enrol the app: the QR code, the link and the setup key.
- Throws:
UserException- AsbeginTotpEnrolment(IClientSessionGyro).
getCodeClockOffset
Gets the drift of a clock the last refused verification code of this session would have been right for (CC-FIX-SIGNIN-TOTP-ENROL, item 9): afterverifySecondFactor(IClientSessionGyro, String, String, int)orconfirmTotpEnrolment(IClientSessionGyro, String)answeredINVALID_CODEfor a code that matches a time step outside the verifier's window but within 5 minutes of this server's clock. Nothing was accepted; the screen names the drift, so that the user checks the clock of the phone - or the server's - instead of guessing.The default names none.
- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.- Returns:
- The seconds the clock of the code is off this server's: positive when ahead, negative when behind; zero when the last code of the session was accepted, was plainly wrong, or there was none.
enrolPasskeySecondFactor
Makes a passkey the second factor of the user (CC-FIX-SIGNIN-2FA-CHOICE): the user chose a passkey on the choice of a second factor, and this session has registered one for the user a short time ago (IUserAuthenticationPasskeys.finishPasskeyRegistration(IClientSessionGyro, String, String)) - for the user whose sign-in waits for the enrolment of a second factor, or for the user it has signed in, after a recent sign-in. A passkey is accepted with user verification only: it is a second factor as an authenticator app is (ruling M-11). The account has a second factor from this moment on; the recovery codes are made with its first one, and the trust of every device of the user for MFA ends, asconfirmTotpEnrolment(IClientSessionGyro, String)does. When the sign-in waited for this enrolment, the user is signed in and recorded in the session now, with the proofSignInPolicy.METHOD_PASSKEY.The default answers
SECOND_FACTOR_METHOD_NOT_ALLOWED: an implementation without passkeys as a second factor.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.- Returns:
- The recovery codes of the account, returned here once; empty when the account had a second factor already, whose recovery codes it keeps.
- Throws:
UserException- WithSECOND_FACTOR_NOT_ENROLLEDwhen this session registered no passkey of the user a short time ago;RECENT_SIGNIN_REQUIRED;SECOND_FACTOR_METHOD_NOT_ALLOWEDwhen the policy has no passkey or no second factor at all; the result of a client source that is held back; or a server, application or system result.
setPreferredSecondFactor
Sets the second factor a sign-in of the user this session has signed in asks for first ("Ask me first for", CC-FIX-SIGNIN-2FA-CHOICE):getSignInMethods(IClientSessionGyro)then lists it first. The sign-in of the session must be recent.The default sets nothing.
- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.method- The method,SignInPolicy.METHOD_PASSKEYorSignInPolicy.METHOD_TOTP, one the user has; null for none: the strongest the user has is asked for first.- Returns:
- true when it is set.
regenerateRecoveryCodes
Replaces the recovery codes of the user this session has signed in: every code made before is dead, used or not. The sign-in of the session must be recent, and the session must have verified a second factor of the user: a code, or a passkey.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.- Returns:
- The new recovery codes, returned here once.
- Throws:
UserException- WithRECENT_SIGNIN_REQUIRED;SECOND_FACTOR_NOT_ENROLLED;SECOND_FACTOR_REQUIREDwhen the sign-in of the session verified no second factor; or a server, application or system result.
removeSecondFactor
Removes a second factor of the user this session has signed in: for the authenticator app the secret, every recovery code and the trust of every device. The sign-in of the session must be recent, and the session must have verified a second factor of the user: a code, or a passkey.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.method- The method to remove,SignInPolicy.METHOD_TOTP.- Returns:
SUCCESSwhen it is removed;RECENT_SIGNIN_REQUIRED;SECOND_FACTOR_NOT_ENROLLED;SECOND_FACTOR_REQUIREDwhen the sign-in of the session verified no second factor;SECOND_FACTOR_METHOD_NOT_ALLOWEDfor a method this server cannot do; or a server, application or system result.- Throws:
NullPointerException- Ifmethodis null.
cancelPendingSignIn
Ends the sign-in that waits in this session, whatever it waits for - its second factor, its passkey, the enrolment of either - and the enrolment that waits: the user goes back to the start. Nothing happens when nothing waits.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.
getSecondFactorProof
Gets the proof that this session's sign-in verified a second factor: the MFA proof of HUB-DESIGN 7.4 (ruling RB-11), which a session transfer carries.- Parameters:
clientGyro- The Client Session Gyro that is the cause of this request.- Returns:
- The proof,
MFAProof.NONEwhen the sign-in verified none - among them the sign-in of a trusted device, which was asked for none. A passkey gives the proof of the methodMFAProof.METHOD_PASSKEY. A proof that is no longerfreshis returned as it is; it is the sender that does not send it.