All Events API webhook requests from SoFi Tech Solutions are authenticated using a JWT with the HS256 algorithm. This ensures that requests are genuinely from SoFi Tech Solutions and haven't been tampered with.
Your server that receives requests for the configured URL(s) should accept traffic over HTTPS and use SSL/TLS. (SoFi Tech Solutions supports TLS 1.2.) In addition to in-transit encryption, you must also perform validation on the messages received on these endpoints to ensure that they are indeed from SoFi Tech Solutions.
Validation involves a JWT (JSON web token) which involves a shared-secret key.
JWT Validation
Below is an example request validated with a JWT:
POST /Authorization HTTP/1.1
Host: localhost:3150
X-Request-ID: 92c341e2-8b50-45bb-805c-8d0aa76124b8
Encryption-Type: JWT-HS256
Accept-Encoding: gzip, deflate
Content-Length: 380
Accept: */*
User-Agent: python-requests/2.9.1
Connection: keep-alive
Date: 20201110:163953UTC
User-ID: galileo
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnYWxpbGVvIiwiaWF0IjoxNjA1MDUxNTkzLCJleHAiOjE2MDUwNTE1OTZ9.jjHsPgAOZc13EGAGeqVHVHH0Nu_ajE5XpDcbDYmS1GI
{
"balance": "195.70",
"merch_name": "Target 2400 South 200 West",
"network": "M",
"timestamp": "20101108:201512UTC",
"cur_code": "840",
"tran_type": 5,
"prn": "155174792582",
"prod_id": 5042,
"amount": -8.95,
"blank": null,
"mcc": "4678",
"merch_num": "321654321654",
"prog_id": 511,
"type": "auth",
"id": "M.auth.2994428",
"tran_id": "2994428",
"merch_loc": "Salt Lake City, UT"
}
How you implement this depends on the language and library you use, but it might look something like this if you use Python:
import jwt
# Shared with SoFi Tech Solutions
secret_key = 'wow_i_should_encrypt_this'
# This library wants us to ignore the 'Bearer' part, as we should
token = request.headers['Authorization'].split(' ')[1]
try:
jwt.decode(
token,
secret_key,
issuer=request.headers['User-ID'],
algorithms=['HS256'] # Won't change for JWT
)
except jwt.ExpiredSignatureError:
print('Oh no, the JWT is expired!')
raise
except jwt.DecodeError:
print("Oh no, this request probably isn't from SoFi Tech Solutions!")
raise

