📜 ⬆️ ⬇️

Loyalty cards. Google Pay API for Passes in ASP.NET

Bank card storage applications are rapidly entering our lives thanks to Apple Wallet and Google Pay. In addition to banking platforms, both platforms also allow you to work with other types of cards - loyalty cards, gift cards, event tickets, boarding passes, etc.




Working in a company that services one rather big retail network, I had to integrate the loyalty cards of this network into Apple Wallet and Google Pay. And if Apple Wallet had to tinker only because the integration layer was rather multifunctional, then with Google Pay most of the effort and nerve cells were spent on sorting out the documentation, finding the right tools and developing the first proof of concept. Although overall the rest of the work went much faster than for the Apple Wallet, I spent the day trying to figure out how to start the service, so I wouldn't mind if someone wrote a similar article before me.

1. materiel


Loyalty cards are presented using two entities - Loyalty Class and Loyalty Object.


In order to receive a card, the user must follow the link format
www.android.com/payapp/savetoandroidpay / {JWT} , where JWT is a token that holds JSON with LoyaltyClass data. But since the length of the URL has limitations, it is recommended to first create the Loyalty Class, if its structure contains many characters.

If you need to update the map due to changes in the template, styles, the need to add or change text fields, you can do this using the API. It is only necessary to perform a POST request with the new version of the map, Google services themselves synchronize all the applications of users who have this map saved.


2. Tools and documentation


The problem was that all the examples in the Google Pay API for Passes documentation were exclusively for Java, PHP, and Python, and the documentation itself strongly recommended “using client libraries to simplify the process” of working with the API.


Following this advice, I happily went to nuget, but the library for Google Pay was not there. Glory to Brin, the first line in google for the query google pay for passes dotnet produced the Google Pay API for Passes utility libraries page, which contained what I needed, though in the ZIP archive format in which the .net project from generated class, which is a wrapper for the Google Pay API - Google Pay API for Passes Client library .


Judging by the presence of the Google.Apis.Walletobjects.v1.1.9.2.00.nuspec file in the project, the deployment of the nuget package was still included in the plans of the Google team. Having opened this file in search of documentation, I did not find anything concrete, and some links that were in the description section were sent to non-existent pages.
')

3. Getting access token


To start working directly with Google Pay API for Passes, you need to get access token, for this you need:

  1. Have a Google Merchant Account, which you can get here
  2. Create a Service Account, get for it a file with credentials - json document with service account details, including ID, email, private key, etc. As recommended by the documentation, you need to store this file in a protected place.
  3. Link Merchant Account and Service Account in Google Merchant Center

Using this file, you can log in using the Google.Apis.Auth.OAuth2 library:

private await Task<string> GetOAuthToken() {         string serviceAccountFile = string.Empty;         serviceAccountFile = ConfigurationManager.AppSettings["GooglePayServiceAccountConfigPath"];        /*              Credential, GoogleCredential              Service Account,   ,      scopes API,             */         var credential = GoogleCredential.FromFile(serviceAccountFile)                            .CreateScoped(WalletobjectsService.Scope.WalletObjectIssuer);        /*        Access token        ,   GetAccessTokenForRequestAsync         ,               */         var token = async credential.UnderlyingCredential.GetAccessTokenForRequestAsync();         return token; } 

4. Creating a map


In order to create a loyalty card, you must first create a Loyalty Class. Loyalty Class can be created using the API, or using the Google Merchant Center web interface. Attention should be paid to the class name, as this name must be unique in the Google Pay infrastructure.

After creating the Loyalty Class, you can create a Loyalty Object. To do this, we will need the library that we added to the project earlier: create the request object, specify the OAuth token, transfer the created LoyaltyObject object, execute the request:

 public GooglePayApiService() { // ,    Merchant Account IssuerId = ConfigurationManager.AppSettings["GooglePayIssuerId"]; _wobService = new WalletobjectsService(); } private async Task<LoyaltyObject> ConvertLoyaltyObjectFromTemplate(GooglePayPassTemplate template) { string id = $"{IssuerId}.{template.SerialNumber}"; string loyaltyClassName = ConfigurationManager.AppSettings["GooglePayStoreCardClassName"];     var loyaltyClass = await GetLoyaltyClass(loyaltyClassName); var result =  new LoyaltyObject { Id = id, AccountName = template.AccountName,          Barcode = new Barcode          {          AlternateText = template.BarcodeText,               Value = template.SerialNumber,               Type = "pdf417"          },          Kind = "walletObject#loyaltyObject",          ClassId = loyaltyClass.Id,          ClassReference = loyaltyClass,          State = "active"     };     return result; } private async Task<LoyaltyObject> CreateLoyaltyObject(LoyaltyObject loyaltyObject) { var saveRequest = _wobService.Loyaltyobject.Insert(loyaltyObject); saveRequest.OauthToken = await GetOAuthToken(); var savedObject = await saveRequest.ExecuteAsync(); return savedObject; } 

The GooglePayPassTemplate in this example is the DTO, which stores the card template for the user, which is generated by a separate developed service.

5. Map update


Here the principle is the same as at creation: we generate a request, we transfer the updated LoyaltyObject object, we execute:

 private async Task<LoyaltyObject> UpdateLoyaltyObject(LoyaltyObject loyaltyObject) { var updateRequest = _wobService.Loyaltyobject.Update(loyaltyObject, loyaltyObject.Id);           updateRequest.OauthToken = await GetOAuthToken(); var savedObject = await updateRequest.ExecuteAsync(); return savedObject; } 

After completing the request, the card in the applications of users who have it installed will be updated after a few seconds if the device is on the network and there is an Internet connection.



6. Generate JWT


To install the card, you need to redirect the user to the link www.android.com/payapp/savetoandroidpay / {JWT} . Description of the token structure can be found at this link .


The token is signed with the RSA-SHA256 signature, which can be generated using the same file with the Service Account credentials:

 public static class JwtHelper { public static string CreateJwtForLoyaltyObject(LoyaltyObject loyaltyObject) { /*       credential   ,         */ ServiceAccountCredential credential; var now = DateTime.UtcNow; DateTime unixEpoch = new DateTime(1970, 01, 01); // 1970-01-01 00:00:00 UTC var secondsSinceEpoch = (int)Math.Round((now - unixEpoch).TotalSeconds); string serviceAccountFile = serviceAccountFile = ConfigurationManager.AppSettings["GooglePayServiceAccountConfigPath"]; using (var fs = new FileStream(serviceAccountFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { credential = ServiceAccountCredential.FromServiceAccountData(fs); } /*    JwtPayload,     payload-a  JWT */ var jwtPayload = new JwtPayload { iat = secondsSinceEpoch, iss = credential.Id, payload = new JwtInternalPayload { loyaltyObjects = new[] { new LoyaltyObjectPayload { id = loyaltyObject.Id } } } }; string header = @"{""alg"":""RS256"",""typ"":""JWT""}"; string payload = JsonConverter.SerializeObject(jwtPayload); string base64Header = EscapedBase64(Convert.ToBase64String(Encoding.UTF8.GetBytes(header))); string base64Payload = EscapedBase64(Convert.ToBase64String(Encoding.UTF8.GetBytes(payload))); //        Signature string signature = EscapedBase64(credential.CreateSignature( Encoding.UTF8.GetBytes($"{base64Header}.{base64Payload}") )); var token = $"{base64Header}.{base64Payload}.{signature}"; return token; } private static string EscapedBase64(string base64) { return base64.Replace('+', '-') .Replace('/', '_') .Replace("=", ""); } } 

Conclusion


In this article, we walked through the basics of working with the Google Pay API for Passes: setting up accounts, connecting to an API, creating a Loyalty Class and Loyalty Object.

If the UFO favors, I’ll tell you separately about how to work with Apple Wallet (everything is more difficult in terms of implementation), how to make friends with Apple Wallet with Google Pay in one web service and not experience pain.


useful links


Source: https://habr.com/ru/post/434486/


All Articles