Overview
Please review the Getting Started article for helpful information on setup, including obtaining the credentials necessary for Authorization.
SVB APIs rely on OAuth for authentication. Before you can interact with any SVB APIs, you need to obtain an OAuth JWE token (JSON web encrypted token)(https://datatracker.ietf.org/doc/html/rfc7516) following IANA reserved claims. Tokens issued are short-lived and valid specific to the scope issued.
SVB API's uses JSON Web signature(JWS) (https://datatracker.ietf.org/doc/html/rfc7515) for non-repudiation, it MUST be signed using client secret and detached the content for the resource calls. The JWS signature of the body of the payload must be send over x-jws-signature custom HTTP header. Please find a walkthrough for generating the JWS here.
SVB opted for the detached signature option because:
- it avoids obfuscating request/response bodies by wrapping them in a JWS envelope
- request/responses that provide a malformed x-jws-signature header can be rejected before ever reading the full HTTP body
Note: for added security, clients can optionally request SVB to setup mTLS authentication or IP address/range filtering
OAuth 2.0
SVB APIs use the OAuth 2.0 protocol for authentication and authorization. The OAuth Client Credentials grant type is used by clients to obtain an JSON Web encrypted token outside of the context of a user.
To access the SVB resource server, the client application must authorize itself with valid client credentials. SVB authorization service uses the client credentials grant in order to authorize machine-to-machine requests. The steps for the process are as follows:
1.An app makes a POST request to the authorization service and specifies the following parameters:
NAME | DESCRIPTION |
---|---|
Authorization | In order to indicate that the app is authorized to make the request, the Authorization header for this request is set as “Basic BASE64(CLIENT_ID:CLIENT_SECRET)“, where BASE64(CLIENT_ID:CLIENT_SECRET) is the base64 representation of the app client ID and app client secret, concatenated with a colon. SVB will provide a valid CLIENT_ID and CLIENT_SECRET as part of the client on-boarding process. |
grant_type | Set to “client_credentials” for this grant type. |
content_type | Set to “application/x-www-form-urlencoded”. |
scope | The scope of the token (accepted values: "ach", "wires", or "vcn"). |
2.The authorization server returns a JSON object with the following keys:
NAME | DESCRIPTION |
---|---|
token_type | Set to “Bearer” |
issued_at | Refers to the UNIX timestamp of our system. |
access_token | A valid JWE(json web encrypted token)(https://datatracker.ietf.org/doc/html/rfc7516) following IANA reserved claims. |
expires_in | The length of time (in seconds) for which the provided access token is valid. |
Authorization Example
The client app uses the JWE token to make requests to an associated SVB resource server. The SVB resource server validates the received token and, upon a successful validation, executes the required action depending on the type of the resource call.
Sample Creation Request in CURL |
---|
curl --location --request POST 'https://api.svb.com/v1/security/oauth/token' \ --header 'Authorization: Basic BASE64(CLIENT_ID:CLIENT_SECRET) ' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=wires' |
Sample Creation Response |
---|
{ "token_type": "Bearer", "issued_at": 1625624530, "access_token": "xxxxxxxx", "scope": "wires", "expires_in": 600 } |
Error scenarios
Invalid Username and Password: If the application consumer provides an invalid app client id or secret, the authorization server will return HTTP 401.
Example: Request |
---|
curl --location --request POST https://api.svb.com/v1/security/oauth/token' \ --header 'Authorization:Basic BASE64(INVALID CLIENT_ID:CLIENT_SECRET) ' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=wires' |
Example: Response |
---|
{ "error": "invalid_client", "error_description": "Client credentials are invalid.", "error_uri": "http://developer.svb.com/errors" } |
Missing Authorization Header: If the application consumer miss Authorization header, the authorization server will return HTTP 401 .
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1/security/oauth/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' |
Example: Response |
---|
{ "error": "invalid_client", "error_description": "Client credentials are invalid.", "error_uri": "http://developer.svb.com/errors" } |
Invalid Content-Type: If the application consumer provides an invalid content type, the authorization server will return HTTP 415 Unsupported Media Type.
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1/security/oauth/token' \ --header 'Authorization:Basic BASE64( CLIENT_ID:CLIENT_SECRET) ' \ --header 'Content-Type: application/json' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=wires' |
Example: Response |
---|
{ "error": "invalid_request", "error_description": "Mandatory param Content-Type is invalid.", "error_uri": "http://developer.svb.com/errors" } |
Invalid Grant-Type: If the application consumer provides no grant type, authorization server will return HTTP 400.
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1/security/oauth/token' \ --header 'Authorization:Basic BASE64( CLIENT_ID:CLIENT_SECRET) ' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'scope=wires' |
Example: Response |
---|
{ "error": "invalid_request", "error_description": "Mandatory param grant_type is null.", "error_uri": "http://developer.svb.com/errors" } |
Incorrect Grant-Type: If the application consumer provides an incorrect grant type, the authorization server will return HTTP 400.
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1/security/oauth/token' \ --header 'Authorization:Basic BASE64( CLIENT_ID:CLIENT_SECRET) ' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=authorization_code' \ --data-urlencode 'scope=wires' |
Example: Response |
---|
{ "error": "unsupported_grant_type", "error_description": "Mandatory param grant_type is invalid.", "error_uri": "http://developer.svb.com/errors" } |
Non-existent Grant-Type: If the application consumer provides an incorrect grant type, the authorization server will return HTTP 400.
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1/security/oauth/token' \ --header 'Authorization:Basic BASE64( CLIENT_ID:CLIENT_SECRET) ' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=test' \ --data-urlencode 'scope=wires' |
Example: Response |
---|
{ "error": "unsupported_grant_type", "error_description": "Mandatory param grant_type is invalid.", "error_uri": "http://developer.svb.com/errors" } |
Invalid request Verb: If the application consumer provides an incorrect request verb, the authorization server will return HTTP 405.
Example: Request |
---|
curl --location --request GET 'https://api.svb.com/v1/security/oauth/token' \ --header 'Authorization:Basic BASE64( CLIENT_ID:CLIENT_SECRET) ' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=wires' |
Example: Response |
---|
{ "error": "invalid_request", "error_description": "Method GET not allowed.", "error_uri": "http://developer.svb.com/errors" } |
Invalid client with revoked/not approved app: If the application consumer provides credentials which is revoked/not approved app, the authorization server will return HTTP 401.
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1//security/oauth/token' \ --header 'Authorization:Basic BASE64( REVOKED CLIENT_ID:CLIENT_SECRET) ' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=wires' |
Example: Response |
---|
{ "error": "invalid_client", "error_description": "API key has not been approved or has been revoked", "error_uri": "http://developer.svb.com/errors" } |
Resource Server Error Scenarios:
If the application consumer provides an invalid authorization type, SVB resource server will return HTTP 401.
Missing Authorization header
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1/payment/wires' \ --header 'Content-Type: application/json' \ --header 'x-jws-signature: eyJraWQiOiJjMzlkMjAxZC05MDIwLTQzOGMtYjA2YS0yMzljNjY3ZDhkZWQiLCJ0eXAiOiJKT1NFIiwiYWxnIjoiSFMyNTYifQ..jQHRD_9DbY5hjTzRopnH8_gsqcLz44t1uP6on5ykUIU' \ --header 'Content-Type: text/plain' \ --data-raw '{ "debit_account": "3300187974", "amount": { "currency_code": "USD", "value": "12.78" }, "processing_date": "2021-06-30", "beneficiary_details": { "beneficiary_account": "65768776", "beneficiary_name": { "given_name": "Ntest OP" }, "beneficiary_address": { "country": "US" } }, "beneficiary_bank": { "bank_name": "Wells Fargo", "bank_address": { "country": "US" }, "routing_number": "021000021" }, "payment_details": { "reason_for_payment": "testwires30June01", "bank_instruction": "BankInst30June01" } }' |
Invalid JWE token value after Bearer
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1/payment/wires' \ --header 'Authorization: Bearer INVALID JWE Token' \ --header 'Content-Type: application/json' \ --header 'x-jws-signature: eyJraWQiOiJjMzlkMjAxZC05MDIwLTQzOGMtYjA2YS0yMzljNjY3ZDhkZWQiLCJ0eXAiOiJKT1NFIiwiYWxnIjoiSFMyNTYifQ..jQHRD_9DbY5hjTzRopnH8_gsqcLz44t1uP6on5ykUIU' \ --data-raw '{ "debit_account": "3300187974", "amount": { "currency_code": "USD", "value": "12.78" }, "processing_date": "2021-06-30", "beneficiary_details": { "beneficiary_account": "65768776", "beneficiary_name": { "given_name": "Ntest OP" }, "beneficiary_address": { "country": "US" } }, "beneficiary_bank": { "bank_name": "Wells Fargo", "bank_address": { "country": "US" }, "routing_number": "021000021" }, "payment_details": { "reason_for_payment": "testwires30June01", "bank_instruction": "BankInst30June01" } }' |
Missing JWE token after Bearer
Example: Request |
---|
curl --location --request POST 'https://api.svb.com/v1/payment/wires' \ --header 'Authorization: Bearer' \ --header 'Content-Type: application/json' \ --header 'x-jws-signature: eyJraWQiOiJjMzlkMjAxZC05MDIwLTQzOGMtYjA2YS0yMzljNjY3ZDhkZWQiLCJ0eXAiOiJKT1NFIiwiYWxnIjoiSFMyNTYifQ..jQHRD_9DbY5hjTzRopnH8_gsqcLz44t1uP6on5ykUIU' \ --data-raw '{ "debit_account": "3300187974", "amount": { "currency_code": "USD", "value": "12.78" }, "processing_date": "2021-06-30", "beneficiary_details": { "beneficiary_account": "65768776", "beneficiary_name": { "given_name": "Ntest OP" }, "beneficiary_address": { "country": "US" } }, "beneficiary_bank": { "bank_name": "Wells Fargo", "bank_address": { "country": "US" }, "routing_number": "021000021" }, "payment_details": { "reason_for_payment": "testwires30June01", "bank_instruction": "BankInst30June01" } }' |
Example Response for various scenarios above
Example: Request |
---|
{ "name": "INVALID_TOKEN", "id": "161409e4-e35c-48e4-9f51-5b0fc1e92874", "message": "Token is invalid", "time": "2022-01-27T19:17:36.483Z", "errors": [ { "keyword_location": "Authorization", "in": "header", "message": "Token is invalid" } ], "links": [ { "href": "https://developer.svb.com/errors/INVALID_TOKEN", "rel": "error_details", "enc_type": "application/json" } ] } |