Skip to content

πŸ”‘ C# helper utility that sign HTTP Authorization Scheme for API authentication

License

Notifications You must be signed in to change notification settings

GovTechSG/csharp-apex-api-security

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

89 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

APEX API C# Security Utility

Build Status PRs Welcome MIT License

A C# helper utility that construct and sign HTTP Authorization header scheme for API authentication and verification.

Table of Contents

Getting Started

Prerequisites

  • .NET Framework 4.6.1
  • Visual Studio 2019 Community
  • NUnit Framework 3.13+

Make sure that all unit test cases are passed before using the library.

Installing NUnit (Important : Windows Only)

For windows users , NUnitTestAdapter have to be installed before you can run the test cases succcessfully.

  1. From Tools menu, use Library Package Manager and select Manage NuGet packages for solution.

  2. In the left panel, select Online

  3. Locate (search for) NUnit 3.0 Test Adapter in the center panel and highlight it

  4. Click install, and select existing project ApiSecuritySolution to add the adapter.

Using the QueryData and FormData Class

The ApiUtilLib Library provide the utility class QueryData to construct request Query String and Form Data.

Generate QueryString

    var queryData = new QueryData();

    queryData.Add("clientId", "1256-1231-4598");
    queryData.Add("accountStatus", "active");
    queryData.Add("txnDate", "2017-09-29");

    string queryString = queryData.ToString();

    string baseUrl = string.Format("https://example.com/resource{0}", queryString);
    // https://example.com/resource?clientId=1256-1231-4598&accountStatus=active&txnDate=2017-09-29

Generate FormData

    var formData = new FormData();

    formData.Add("phoneNo", "+1 1234 4567 890");
    formData.Add("street", "Hellowood Street");
    formData.Add("state", "AP");

    string formData = formData.ToString();
    // phoneNo=%2B1+1234+4567+890&street=Hellowood+Street&state=AP

NOTE

For formData parameter used for Signature generation, the key value parameters do not need to be URL encoded, When you use this client library method ApiAuthorization.HttpRequest, it will do the url-encoding during the HTTP call

How to Generate L1 Authorization Header

public void L1Sample()
{
    var URL = "https://{gatewayName}.api.gov.sg/api/v1/resource";
    var APP_NAME = "{appName}";
    var APP_SECRET = "{appSecret}";

    // prepare form data
    var formData = new FormData();
    formData.Add("q", "how to validate signature in pdf");
    formData.Add("ei", "yAr8YLmwCM_Fz7sPsKmLoAU");

    var authParam = new AuthParam()
    {
        url = new Uri($"{URL}"),
        httpMethod = HttpMethod.POST,

        appName = APP_NAME,
        appSecret = APP_SECRET,

        formData = formData
    };

    // get the authorization token for L1
    var authToken = ApiAuthorization.TokenV2(authParam);

    Console.WriteLine($"\n>>> BaseString :: '{authToken.BaseString}'<<<");
    Console.WriteLine($"\n>>> Authorization Token :: '{authToken.Token}'<<<");

    // make api call with authToken.Token
}

Supported Private Key File Type

  1. .pem/.key - pkcs#1 base64 encoded text file
  2. .pem/.key - pkcs#8 base64 encoded text file
  3. .p12/.pfx - pkcs#12 key store

How to Generate L2 Authorization Header

public void L2Sample()
{
    var URL = "https://{gatewayName}.api.gov.sg/api/v1/resource";
    var APP_NAME = "{appName}";
    var PRIVATE_KEY_FILE_NAME = "privateKey.key";
    var PRIVATE_KEY_PASSPHRASE = "{passphrase}";

    // get the private key from pem file (in pkcs1 format)
    var privateKey = ApiAuthorization.GetPrivateKey(PRIVATE_KEY_FILE_NAME, PRIVATE_KEY_PASSPHRASE);

    // prepare queryString
    var queryData = new QueryData();
    queryData.Add("view", "net-5.0");
    queryData.Add("system", "C# sample code");

    // get url safe querystring from ToString()
    Console.WriteLine($">>> Query String >>>{queryData.ToString()}<<<");

    // prepare form data
    var formData = new FormData();
    formData.Add("name", "peter pan");
    formData.Add("age", "12");

    var authParam = new AuthParam()
    {
        url = new Uri($"{URL}{queryData.ToString()}"),
        httpMethod = HttpMethod.POST,

        appName = APP_NAME,
        privateKey = privateKey,

        formData = formData
    };

    // get the authorization token for L1
    var authToken = ApiAuthorization.TokenV2(authParam);

    Console.WriteLine($"\n>>> BaseString :: '{authToken.BaseString}'<<<");
    Console.WriteLine($"\n>>> Authorization Token :: '{authToken.Token}'<<<");

    // make api call with authToken.Token
}

How to Generate L21 Authorization Header

(for cross zone api from internet to intranet)

public void L21Sample()
{
    var URL_WWW = "https://{www_gatewayName}.api.gov.sg/api/v1/resource";
    var APP_NAME_WWW = "www_appName";
    var PRIVATE_KEY_FILE_NAME = "www_privateKey.key");
    var PRIVATE_KEY_PASSPHRASE = "{password}";

    var URL_WOG = "https://{wog_gatewayName}.api.gov.sg/api/v1/resource";
    var APP_NAME_WOG = "{wog_AppName}";
    var APP_SECRET_WOG = "{wog_appSecret}";

    // get the private key from pem file (in pkcs1 format)
    var privateKey = ApiAuthorization.GetPrivateKey(PRIVATE_KEY_FILE_NAME, PRIVATE_KEY_PASSPHRASE);

    // prepare queryString
    var queryData = new QueryData();
    queryData.Add("view", "net-5.0");
    queryData.Add("system", "C# sample code");

    // prepare form data
    var formData = new FormData();
    formData.Add("name", "peter pan");
    formData.Add("age", "12");

    // prepare the parameters
    var authParam = new AuthParam()
    {
        url = new Uri($"{URL_WWW}{queryData.ToString()}"),
        httpMethod = HttpMethod.POST,

        appName = APP_NAME_WWW,
        privateKey = privateKey,

        formData = formData,

        nextHop = new AuthParam()
        {
            url = new Uri($"{URL_WOG}{queryData.ToString()}"),

            appName = APP_NAME_WOG,
            appSecret = APP_SECRET_WOG
        }
    };

    // get the authorization token for L21
    var authToken = ApiAuthorization.TokenV2(authParam);

    Console.WriteLine($"\n>>>{tag}<<< BaseString :: '{authToken.BaseString}'<<<");
    Console.WriteLine($"\n>>>{tag}<<< Authorization Token :: '{authToken.Token}'<<<");

    // make api call with authToken.Token
}

How to Generate L12 Authorization Header

(for cross zone api from intranet to internet)

public void L12Sample()
{
    var URL_WOG = "https://{wog_gatewayName}.api.gov.sg/api/v1/reslource";
    var APP_NAME_WOG = "{wog_appName}";
    var APP_SECRET_WOG = "{wog_AppSecret}";

    var URL_WWW = "https://{www_appName}.api.gov.sg/api/v1/resource";
    var APP_NAME_WWW = "{www_AppName}";
    var PRIVATE_KEY_FILE_NAME = "Certificates/www_privateKey.pkcs8");
    var PRIVATE_KEY_PASSPHRASE = "{passphrase}";

    // get the private key from pem file (in pkcs8 format)
    var privateKey = ApiAuthorization.GetPrivateKey(PRIVATE_KEY_FILE_NAME, PRIVATE_KEY_PASSPHRASE);

    // prepare queryString
    var queryData = new QueryData();
    queryData.Add("view", "net-5.0");
    queryData.Add("system", "C# sample code");

    // prepare form data
    var formData = new FormData();
    formData.Add("name", "peter pan");
    formData.Add("age", "12");

    // prepare the token parameters
    var authParam = new AuthParam()
    {
        url = new Uri($"{URL_WOG}{queryData.ToString()}"),
        httpMethod = HttpMethod.POST,

        appName = APP_NAME_WOG,
        appSecret = APP_SECRET_WOG,

        formData = formData,

        nextHop = new AuthParam()
        {
            url = new Uri($"{URL_WWW}{queryData.ToString()}"),

            appName = APP_NAME_WWW,
            privateKey = privateKey,
        }
    };

    // get the authorization token
    var authToken = ApiAuthorization.TokenV2(authParam);

    Console.WriteLine($"\n>>> BaseString :: '{authToken.BaseString}'<<<");
    Console.WriteLine($"\n>>> Authorization Token :: '{authToken.Token}'<<<");

    // make api call with authToken.Token
}

Release

Contributing

  • For more information about contributing PRs and issues, see CONTRIBUTING.md.

License

MIT LICENSE

References