/oauth1-signer-swift

Zero dependency library for generating a Mastercard API compliant OAuth signature.

Primary LanguageSwiftMIT LicenseMIT

oauth1-signer-swift

maintenance-status

Table of Contents

Overview

Zero dependency library for generating a Mastercard API compliant OAuth signature.

Compatibility

Swift 4.2

References

Usage

Prerequisites

Before using this library, you will need to set up a project in the Mastercard Developers Portal.

As part of this set up, you'll receive credentials for your app:

  • A consumer key (displayed on the Mastercard Developer Portal)
  • A private request signing key (matching the public certificate displayed on the Mastercard Developer Portal)

Adding the Library to Your Project

MastercardOAuth1Signer is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'MastercardOAuth1Signer'

You can then import the framework from Swift:

import MastercardOAuth1Signer

Note: Use of this library as a pod requires Xcode 10 or later.

Loading the Signing Key

You can use the utility KeyProvider.swift to create a SecKey object representing your developer private key. For that, simply pass in a bundle path for your PKCS#12 key store along with its password:

let signingKey = KeyProvider.loadPrivateKey(fromPath: certificatePath, keyPassword: "<<PASSWORD>>")!

Creating the OAuth Authorization Header

OAuth.authorizationHeader

The method that does all the heavy lifting is OAuth.authorizationHeader(). You can call into it directly and as long as you provide the correct parameters, it will return a string that you can add into your request's Authorization header.

let header = try? OAuth.authorizationHeader(forUri: uri, method: method, payload: payloadString, consumerKey: consumerKey, signingPrivateKey: signingKey)

Example

To run the example project, first clone this repo and then pod install from the project directory.

Example usage:

let uri = URL(string: "https://sandbox.api.mastercard.com/service")!
let method = "GET"
let examplePayload: [String: String] = ["languageId": 1,
                                        "geographicId": 0]
let payloadJSON = (try? JSONSerialization.data(withJSONObject: examplePayload, options: [])) ?? Data()
let payloadString = String(data: payloadJSON, encoding: .utf8)

let consumerKey = "<insert consumer key from developer portal>"
let signingKey = "<initialize private key matching the consumer key>"

let header = try? OAuth.authorizationHeader(forUri: uri, method: method, payload: payloadString, consumerKey: consumerKey, signingPrivateKey: myPrivateKey)

let headers: HTTPHeaders = ["Authorization": header!,
                            "Accept": "application/json",
                            "Referer": "api.mastercard.com"]

Integrating with OpenAPI Generator API Client Libraries

OpenAPI Generator generates API client libraries from OpenAPI Specs. It provides generators and library templates for supporting multiple languages and frameworks.

To use MastercardOAuth1Signer with a generated client library in Swift 5, follow the below steps:

  1. Create a new class to which generates and adds an auth header in the URLRequest.
import MastercardOAuth1Signer

class RequestAuthDecorator: NSObject {
    static func addAuthHeaders(request: URLRequest) -> URLRequest {
        var urlRequest = request
        let certificatePath = Bundle(for: RequestAuthDecorator.self).path(forResource: "<<FILENAME>>", ofType: "p12")
        let signingKey = KeyProvider.loadPrivateKey(fromPath: certificatePath!, keyPassword: "<<PASSWORD>>")!
        let consumerKey = "CONSUMER_KEY"
        var payloadString :String? = nil
        if urlRequest.httpBody != nil
        {
            payloadString = String.init(data: urlRequest.httpBody!, encoding: .utf8)
        }
        let header = try? OAuth.authorizationHeader(forUri: urlRequest.url!, method: urlRequest.httpMethod!, payload: payloadString, consumerKey: consumerKey, signingPrivateKey: signingKey)
        urlRequest.setValue(header!, forHTTPHeaderField: "Authorization")
        return urlRequest;
    }
}
  1. Create a subclass of 'URLSessionRequestBuilder' & 'URLSessionDecodableRequestBuilder' and override the 'createUrlRequest' method in both classes to insert the auth header in the request.
class CustomURLSessionRequestBuilder<T>: URLSessionRequestBuilder<T> {
    
    override func createURLRequest(urlSession: URLSession, method: HTTPMethod, encoding: ParameterEncoding, headers: [String : String]) throws -> URLRequest {
        let request: URLRequest = try super.createURLRequest(urlSession: urlSession, method: method, encoding: encoding, headers: headers);
        let requestWithAuthHeader = RequestAuthDecorator.addAuthHeaders(request: request);
        return requestWithAuthHeader;
    }
  
}

class CustomURLSessionDecodableRequestBuilder<T:Decodable>: URLSessionDecodableRequestBuilder<T> {
    
    override func createURLRequest(urlSession: URLSession, method: HTTPMethod, encoding: ParameterEncoding, headers: [String : String]) throws -> URLRequest {
        let request: URLRequest = try super.createURLRequest(urlSession: urlSession, method: method, encoding: encoding, headers: headers);
        let requestWithAuthHeader = RequestAuthDecorator.addAuthHeaders(request: request);
        return requestWithAuthHeader;
    }

}
  1. Create a subclass of 'RequestBuilderFactory' to override 'getBuilder' & 'getNonDecodableBuilder'. Make these methods to return above created 'CustomURLSessionRequestBuilder' & 'CustomURLSessionDecodableRequestBuilder' respectively.
class CustomURLSessionRequestBuilderFactory: RequestBuilderFactory {
    func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
        return CustomURLSessionRequestBuilder<T>.self
    }

    func getBuilder<T:Decodable>() -> RequestBuilder<T>.Type {
        return CustomURLSessionDecodableRequestBuilder<T>.self
    }
}
  1. Open the generated APIs.swift and assign the CustomURLSessionRequestBuilderFactory to requestBuilderFactory in 'OpenAPIClientAPI' class.
    public static var requestBuilderFactory: RequestBuilderFactory = CustomURLSessionRequestBuilderFactory()

See also:

Authors