← Domain guides

Account Recovery

Account Recovery Guide

Description

For an end user, who has Online Banking with NetTeller or Episys, they may recover their username and password via this feature.

API Docs.

Rate Limiting

Banno Enrollment rate limits users via its own database, as well as via NetTeller.

FeatureCore TypeMax by IPMax by Tax Identification Number(TIN)
Account RecoveryNetTeller505
Account RecoverySymXchange505

Once a user has met the “Max by IP” or “Max by TIN” rate limits, that user is then not allowed to re-try for ~24 hours. Note that either rate limit is independent of one another.

Technical Details

The following serves as a technical overview of Enrollment.

Diagram Part 1

Diagram Part 2

And here is a diagram of the flow (editable) for banks (including the updates to unlock during recovery as necessary):

Recovery flow (banks)

And for credit unions (editable):

Recovery flow (credit unions)

POST /recovery/lookup

NetTeller Bank

The purpose of this endpoint is to determine if the user, whose details are presented in the HTTP Request, is eligible to recover their account.

The following steps happen, in order:

  1. From the request, look up in banno_all database whether the institutionId is a SymXchange or NetTeller Institution

  2. Look up the user in core, i.e. SymXchange or BSL

    • Get a list of Customer IDs (CIFs) via jxchange-api for the user’s request-provided TIN

    • For each CIF, look up its details via `jxchange-api. The details include:

      • name
      • optional email
      • list of phone numbers
      • set of NetTeller Ids
      • optional demographic data
    • For each candidate, namely the 4-tuple, (CustomerId, NetTellerId, optional email, and list of phone numbers), get the accounts for the given NetTeller Id via a jxchange-api call

    • Exclude any candidate, namely (CustomerId, NetTellerId, optional email, list of phone numbers, list of accounts) if any account’s number does not match the one supplied in POST /recovery/lookup’s payload

    • At this point, we have a List[Candidates], i.e. 0 or more with a matching Account Number

    • For each candidate, query banno_all.login_accounts to determine if the candidate’s details match an existing Banno User. Only count as a ‘banno user candidate’ if the query results one or more results.

        SELECT
          login_id,
          institution_id,
          user_id,
          aggregation_type,
          customer_id,
          netteller_id,
          username,
          member_number
        FROM login_accounts
        WHERE institution_id = $institutionId
          AND customer_id = $customerId
          AND netteller_id = $netTellerId
          AND aggregation_type = 2 -- NetTeller
          AND active = true
          AND primary_login = true
      
    • Given a List[Candidate] and List[MatchingBannoLoginAccounts], check whether the user can be recovered. See https://github.com/Banno/consumer-enrollment/blob/1.378.0/core/src/main/scala/com/banno/consumerenrollment/backend/modules/recovery/RecoveryInitiationForBanks.scala#L133-L206

    • If an eligible match has been found, check the status of the user via netteller-bsl-service.

      • If the user is Locked or Dormant, then update the sesssion state, which gets stored in the JWT, to indicate that the user cannot be recovered since he/she is locked.
      • If the user is Normal or PasswordNeedsReset, then update the sesssion state to include the phone number, etc.
  3. Check the user’s 2FA Enrollment Status via oob2fa

  4. If the user is enrolled, send a 2FA code and respond w/ HTTP-200; otherwise, respond with an HTTP-202 so that the user gets prompted (by the UI) to enroll in 2FA by supplying Phone Number and Email.

Note that the purpose of the JWT for Enrollment is to achieve authentication, as well as to keep state to maintain, effectively, a session. It is valid for 10 minutes and includes JSON state, e.g. whether the user verified their 2FA Code, etc.

PUT /recovery/oob/verify

NetTeller Bank & Credit Unions
  1. Make HTTP request to oob2fa, Espresso’s service that handles 2FA (enrollment, verification, sending codes, etc), with the 2FA code that the user supplied in the HTTP Request to PUT /recovery/oob/verify.
  2. Record a history event, i.e. send an HTTP request to Team Curry’s ‘history’ web service with the result of the 2FA verification attempt
  3. Send HTTP Response per https://github.com/Banno/consumer-api-docs/blob/master/_recovery/details.swagger.json#L136-L167

POST /recovery/password

NetTeller Bank

The following logic takes place in consumer-enrollment:

  1. Make HTTP request to Espresso’s netteller-bsl-service in order to set a new password for the given user’s NetTellerId
    • Note that this call will fail if the user is locked or dormant per the contract
  2. Check if recovering user is already a Banno User
    • Note - it’s not necessary to be a Banno User before completing Account Recovery. For example, a NetTeller Online user could recover their account despite having not being a Banno User.
      • If the user is already a Banno User
        • update banno_all.login_accounts via a JDBC connection if a particular column is in a bad state
        • make HTTP requests to device-service via HTTP in order to register the user’s device
      • Else, if the user is not yet a Banno User, then
        • insert new rows via JDBC to banno_all to create a new Banno User
        • make HTTP requests to device-service via HTTP in order to register the user’s device
        • persist the user’s encrypted password via an HTTP Request to consumer-login-secrets over HTTP
  3. Record a history event, i.e. send an HTTP request to Team Curry’s ‘history’ web service, indicating that the user saved his/her password.
  4. Invalidate the Recovering User’s session, i.e. prevents subsequent HTTP Requests to POST /recovery/password from succeeding.
  5. Send HTTP Response to mobile-data-services’s api with the recovered user’s details.

The following logic takes place in mobile-data-services’s api:

  1. Use shared code in api to create a fully auth’d JWT
  2. Send HTTP Response w/ fully auth’d JWT