Skip to content
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

LG-13706: Socure KYC Proofer #11093

Merged
merged 10 commits into from
Aug 21, 2024
Merged

LG-13706: Socure KYC Proofer #11093

merged 10 commits into from
Aug 21, 2024

Conversation

matthinz
Copy link
Member

@matthinz matthinz commented Aug 15, 2024

🎫 Ticket

Link to the relevant ticket:
LG-13706

🛠 Summary of changes

This PR adds an implementation of a Proofer for Socure's ID+ service (specifically the KYC module). It does not actually wire the proofer in anywhere--that will come in a future update.

📜 Testing Plan

You can test this manually!

DO NOT USE REAL PII

  1. Log into the Socure dashboard and grab an Id+ API key in the "Sandbox" environment
  2. Make it available in your shell: export SOCURE_IDPLUS_API_KEY=your-secret-api-key
  3. Run this super-advanced test script in the Rails console:
config = Proofing::Socure::IdPlus::Config.new(api_key: ENV['SOCURE_IDPLUS_API_KEY'], base_url: 'https://sandbox.socure.us')

proofer = Proofing::Socure::IdPlus::Proofer.new(config)

result = proofer.proof(
  first_name: 'Fakey',
  last_name: 'McFakerson',
  address1: '1234 Fake St.',
  city: 'Fakeville',
  state: 'CA',
  zipcode: '90210',
  phone: '360-555-1234',
  email: 'testy@example.org',
  dob: '1999-12-31',
  ssn: '999-22-3344',
)

- Basic Proofer implementation for Socure KYC.
- Request / Response classes, error handling, etc.

changelog: Upcoming Features, Identity verification, Implement proofer for Socure KYC
app/services/proofing/socure/id_plus/proofer.rb Outdated Show resolved Hide resolved
app/services/proofing/socure/id_plus/proofer.rb Outdated Show resolved Hide resolved
app/services/proofing/socure/id_plus/proofer.rb Outdated Show resolved Hide resolved
app/services/proofing/socure/id_plus/request.rb Outdated Show resolved Hide resolved
app/services/proofing/socure/id_plus/request.rb Outdated Show resolved Hide resolved
spec/services/proofing/socure/id_plus/request_spec.rb Outdated Show resolved Hide resolved
spec/services/proofing/socure/id_plus/request_spec.rb Outdated Show resolved Hide resolved
def kyc_field_validations
@field_validations ||= kyc('fieldValidations').
each_with_object({}) do |(field, valid), obj|
obj[field.to_sym] = valid.round == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would we ever want this logic to change per-field? or are we set with anything above 0.5 is a pass

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They will literally only send either 0.99 or 0.01, I just figured .round would avoid any weirdness with == and floating points

@matthinz matthinz requested a review from a team August 16, 2024 00:10
VERIFIED_ATTRIBUTE_MAP = {
address: %i[streetAddress city state zip].freeze,
first_name: :firstName,
last_name: :surName,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is offtopic and unimportant, but is camelcase surName our pattern or Socure's? My brain keeps either reading it as surfName, or as two words (since camelCase) and wondering what a sur name is, like it's a foreign word. (I mean, it is, but who knows what a "south name" is?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is Socure's field naming. My thinking is that request/response class speak in terms of Socure's API and their naming, and the proofer class translates that to our conventions / case style

dob: input.dob&.to_date&.to_s,

userConsent: true,
consentTimestamp: 5.minutes.ago.iso8601,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems weird? Do they actually require a timestamp here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They do, and it needs to be recent enough or they will return an error


# > The country or jurisdiction from where the transaction originates,
# > specified in ISO-2 country codes format
countryOfOrigin: 'US',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idle curiosity: does the transaction "originate" from our servers, or the end user? I.e., we know CBP has a lot of users from Mexico; do we need to try to make this dynamic, or is it where we are?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where we are--on Socure's end they are using it for compliance stuff (like, "does GDPR apply to this transaction?")

# XXX: This should be set to the time the user submitted agreement,
# which we are not currently tracking. The "5.minutes.ago" is
# because Socure will reject times "in the future", so we avoid
# our clocks being out of sync with theirs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unimportant but IMHO this comment makes more sense in the code. I wondered why it was set this way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a couple of tickets in the epic to follow up on this:

spec/services/proofing/socure/id_plus/request_spec.rb Outdated Show resolved Hide resolved
stub_request(:post, 'https://example.org/api/3.0/EmailAuthScore').
to_return(
status: 500,
body: 'It works!',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
body: 'It works!',
body: 'It does not work!',

(Only half-joking?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my attempt at humor--Apache will display an "It works!" page by default, meaning that Apache is working, but this page is almost never what you actually want.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, ha! I am all for Apache jokes. I somehow missed this one, but I am 200 OK with this now.

Copy link
Member

@n1zyy n1zyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks reasonable to me. I was able to test it in the console successfully.

Definitely out of scope, if we ever even do it, but with @errors={:reason_codes=>["I919"]} I can't help but think it'd be neat to map those to descriptions. But it's possible these are proprietary and/or there's not really a need to have them in the code? Just a musing for another time.

@matthinz
Copy link
Member Author

This looks reasonable to me. I was able to test it in the console successfully.

Definitely out of scope, if we ever even do it, but with @errors={:reason_codes=>["I919"]} I can't help but think it'd be neat to map those to descriptions. But it's possible these are proprietary and/or there's not really a need to have them in the code? Just a musing for another time.

I think there is an API endpoint we can hit to get the descriptions, but they don't change too much over time, so we could possibly have a static mapping

@matthinz matthinz merged commit e863fe9 into main Aug 21, 2024
2 checks passed
@matthinz matthinz deleted the matthinz/13706-socure-kyc-proofer branch August 21, 2024 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants