Payment API Client

## Overview

---

This API is a gateway for receiving payments through our system. It's ment to simplify external integration between different domains such as credit cards, prepaid cards and value codes.

## Swagger documentation

---

* [VasPublicPaymentApi](https://stage-evc.payex.com/payment-api/swagger-ui.html)

# Public Payment API Client

---

## Prerequisites

---

* Java 11  
* VueJS  
* Maven  
* Postgres

## Project setup

---

vas-payment-api-client  
    ├─┬ backend     → backend module with Spring Boot code  
    │ ├── src  
    │ └── pom.xml  
    ├─┬ frontend    → frontend module with Vue.js code  
    │ ├── src  
    │ └── pom.xml  
    └── pom.xml     → Maven parent pom managing both modules

## Security

---

<details>  
<summary>Oauth2:</summary>

VasPublicPaymentApi requires an OAuth2 access token for interaction.    
This application automatically handles token fetching and refreshing by using [Spring Security](https://docs.spring.io/spring-security-oauth2-boot/docs/current/reference/htmlsingle/#boot-features-security-custom-user-info-client).    
Configuration values are set in [application.yml](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/resources/application.yml):

# "XXX" Should be replaced by value provided by PayEx  
# CLIENT_ID/CLIENT_SECRET/VAS_AUTH_SERVER_URL can also be set in docker-compose.yml as environment variables if running with docker  
# The application will see if environment variables are present, if not fall back to "XXX" values.  
vas-payment-api:  
    oauth2:  
        client:  
            grantType: client_credentials  
            clientId: "${CLIENT_ID}:XXX"  
            clientSecret: "${CLIENT_SECRET}:XXX"  
            accessTokenUri: "${VAS_AUTH_SERVER_URL}:XXX"  
            scope: publicapi   
              

And the implementation of these are located in [Oauth2RestTemplateConfiguration.java](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/java/com/payex/vas/demo/config/security/Oauth2RestTemplateConfiguration.java):

public class Oauth2RestTemplateConfiguration {  
    //...  
    @Bean  
    @ConfigurationProperties("vas-payment-api.oauth2.client")  
    protected ClientCredentialsResourceDetails oAuthDetails() {  
        return new ClientCredentialsResourceDetails();  
    }`

`    @Bean  
    protected RestTemplate restTemplate() {  
        var restTemplate = new OAuth2RestTemplate(oAuthDetails());  
        restTemplate.setInterceptors(ImmutableList.of(externalRequestInterceptor()));  
        restTemplate.setRequestFactory(httpRequestFactory());  
        return restTemplate;  
    }  
    //...  
}  
```  
</details>`

`<details>`

`<summary>HMAC:</summary>`

`The API also requires HMAC authentication to be present in a request.    
In this client the HMAC value is automatically calculated by [HmacSignatureBuilder.java](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/java/com/payex/vas/demo/config/security/HmacSignatureBuilder.java) and added to all outgoing requests in [ExternalRequestInterceptor.java](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/java/com/payex/vas/demo/config/ExternalRequestInterceptor.java)`

`HMAC is implemented using SHA-512 secure hash algorithm. `

`Expected `Hmac` header format is:`

HmacSHA512 ::
````

wheredigestis a Base64 formatted HMAC SHA512 digest of the following string:

METHOD\n  
RESOURCE\n  
USER\  
NONCE\n  
DATE\n  
PAYLOAD\n  

`METHOD (mandatory) the requested method (in upper case) RESOURCE (mandatory) the path to desired resource (without hostname and any query parameters)
NONSE (mandatory) a unique value for each request (UUID) DATE(optional) same as Transmission-Time if provided as seperate header. Uses ISO8601 standard PAYLOAD (optional) body of request `

Example request:

curl -X POST \  
  https://stage-evc.payex.com/payment-api/api/payments/payment-account/balance \  
  -H 'Accept: */*' \  
  -H 'Agreement-Merchant-Id: XXX' \  
  -H 'Authorization: Bearer XXX' \  
  -H 'Hmac: HmacSHA512 user:21a0213e-30eb-85ab-b355-a310d31af30e:oY5Q5Rf1anCz7DRm3GyWR0dvJDnhl/psylfnNCn6FA0NOrQS3L0fvyUsQ1IQ9gQPeLUt9J3IM2zwoSfZpDgRJA==' \  
  -H 'Transmission-Time: 2019-06-18T09:19:15.208257Z' \  
  -H 'Session-Id: e0447bd2-ab64-b456-b17b-da274bb8428e' \  
  -d '{  
 "accountIdentifier": {  
  "accountKey": "7013369000000000000",  
  "cvc": "123",  
  "expiryDate": "2019-12-31",  
  "instrument": "GC"  
 }  
}'  

In this exampleUSERis user andSECRETis secret.

The plain string todigestwould then be:

POST  
/payment-api/api/payments/payment-account/balance  
user  
21a0213e-30eb-85ab-b355-a310d31af30e  
2019-06-18T09:19:15.208257Z  
{  
 "accountIdentifier": {  
  "accountKey": "7013360000000000000",  
  "cvc": "123",  
  "expiryDate": "2020-12-31",  
  "instrument": "CC"  
 }  
}  

The plaindigeststring is then hashed withHmacSHA512algorithm and theSECRET. Finally we Base64 encode the hashed value. This is the finaldigestto be provided in theHmacheader.

FinalHmacheader value:

HmacSHA512 user:21a0213e-30eb-85ab-b355-a310d31af30e:oY5Q5Rf1anCz7DRm3GyWR0dvJDnhl/psylfnNCn6FA0NOrQS3L0fvyUsQ1IQ9gQPeLUt9J3IM2zwoSfZpDgRJA==  

#### Postman example script

In pre-request script copy/paste the following snippet:


`var user = 'user';  
var secret = 'secret';  
var transmissionTime = (new Date()).toISOString();  
var sessionId = guid();`

`var hmac = generateHMAC(user, secret, transmissionTime);  
console.log('hmac: ' + hmac);`

`//Set header values  
pm.request.headers.add({key: 'Hmac', value: hmac });  
pm.request.headers.add({key: 'Transmission-Time', value: transmissionTime });  
pm.request.headers.add({key: 'Session-Id', value: sessionId });`

`function generateHMAC(user, secret, transmissionTime) {`

`    var algorithm = "HmacSHA512";  
    var separator = ":";  
    var method = request.method.toUpperCase();  
    var nonce = generateNonce(); //UUID  
    var date = transmissionTime;  
     
    var uri_path = replaceRequestEnv(request.url.trim()).trim().replace(new RegExp('^https?://[^/]+/'), '/'); // strip hostname  
    uri_path = uri_path.split("?")[0]; //Remove query paramters  
    var payload = _.isEmpty(request.data) ? "" : request.data;  
    var macData = method + '\n'  
        + uri_path + '\n'  
        + user + '\n'  
        + nonce + '\n'  
        + date + '\n'  
        + payload + '\n';`

`    macData = replaceRequestEnv(macData);  
    console.log('data to mac: ' + macData);`

`    var hash = CryptoJS.HmacSHA512(macData, secret);  
    var digest = CryptoJS.enc.Base64.stringify(hash);  
    return algorithm + " " + user + separator + nonce + separator + digest;  
}`

`function replaceRequestEnv(input) { //manually set environments to they are populated before hashing  
    return input.replace(/{{([^)]+)}}/g, function (str, key) {  
        var value = pm.environment.get(key);  
        return value === null ? pm.varables.get(key) : value;  
    });  
}`

`function generateNonce() {  
    return guid();  
}`

`function guid() {  
    function s4() {  
        return Math.floor((1 + Math.random()) * 0x10000)  
            .toString(16)  
            .substring(1);  
    }`

`    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +  
        s4() + '-' + s4() + s4() + s4();  
}`

`

### Security documentation

---

* [OAuth2](https://oauth.net/2/)  
* [Client Credentials](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/)  
* [The RESTful CookBook: HMAC](http://restcookbook.com/Basics/loggingin/)  
* [HMAC - Wikipedia](https://en.wikipedia.org/wiki/HMAC)

## First App run

---

**NB! The application expects a PostgreSQL server to be running on localhost with a usernametestand passwordtestto exist.**    
**This can automatically be configured if PostgreSQL server is started in docker with environment variables
POSTGRES_USER=testandPOSTGRES_PASSWORD=testare set (See [docker-compose.yml](https://github.com/PayEx/vas-payment-api-client/blob/master/docker-compose.yml)).**

Inside the root directory, do a:

mvn clean install  

Run the Spring Boot App:

mvn --projects backend spring-boot:run  

Now go to <http://localhost:8080/> and have a look at your new client.

## Testing application

---

1. Add a new card with provided details from PayEx.  
1. Click on newly added Card  
1. Click on "initiate payment" to create a new transaction

## Build docker image:

---

mvn --projects backend clean compile jib:dockerBuild  

## Deploy to local docker:

---

docker-compose up -d      
Created by Thomas Warren on 2020/01/23 13:25

Tips

If you're starting with XWiki, check out the Getting Started Guide.

Need help?

If you need help with XWiki you can contact: