{"id":19107293,"url":"https://github.com/govtechsg/csharp-apex-api-security","last_synced_at":"2025-04-30T18:45:38.890Z","repository":{"id":33714039,"uuid":"108828272","full_name":"GovTechSG/csharp-apex-api-security","owner":"GovTechSG","description":"🔑  C# helper utility that sign HTTP Authorization Scheme for API authentication","archived":false,"fork":false,"pushed_at":"2022-12-08T14:48:54.000Z","size":2961,"stargazers_count":4,"open_issues_count":3,"forks_count":4,"subscribers_count":28,"default_branch":"master","last_synced_at":"2025-03-30T18:51:14.305Z","etag":null,"topics":["csharp","hmac-sha256","http-signature","rsa-signature"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GovTechSG.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-30T09:21:43.000Z","updated_at":"2021-11-22T10:01:31.000Z","dependencies_parsed_at":"2023-01-15T02:10:52.730Z","dependency_job_id":null,"html_url":"https://github.com/GovTechSG/csharp-apex-api-security","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fcsharp-apex-api-security","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fcsharp-apex-api-security/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fcsharp-apex-api-security/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fcsharp-apex-api-security/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GovTechSG","download_url":"https://codeload.github.com/GovTechSG/csharp-apex-api-security/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251765203,"owners_count":21640150,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","hmac-sha256","http-signature","rsa-signature"],"created_at":"2024-11-09T04:12:02.041Z","updated_at":"2025-04-30T18:45:38.854Z","avatar_url":"https://github.com/GovTechSG.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# APEX API C# Security Utility \n[![Build Status](https://travis-ci.org/GovTechSG/csharp-apex-api-security.svg?branch=master)](https://travis-ci.org/GovTechSG/csharp-apex-api-security)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)\n[![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/GovTechSG/csharp-apex-api-security/blob/master/LICENSE)\n\nA C# helper utility that construct and sign HTTP Authorization header scheme for API authentication and verification.\n\n## Table of Contents\n- [Getting Started](#getting-started)\n    * [Prerequisites](#prerequisites)\n    * [Query String and FormData Class](#using-the-querydata-and-formdata-class)\n        + [Generate QueryString](#generate-querystring)\n        + [Generate FormData](#generate-formdata)\n    * [Constructing L1 Authorization Header](#how-to-generate-l1-authorization-header)\n    * [Supported Private Key File Type](#supported-private-key-file-type)\n    * [Constructing L2 Authorization Header](#how-to-generate-l2-authorization-header)\n    * [Cross Zone API from Internet to Intranet](#how-to-generate-l21-authorization-header)\n    * [Cross Zone API from Intranet to Internet](#how-to-generate-l12-authorization-header)\n- [Release](#release)\n- [Contributing](#contributing)\n- [License](#license)\n- [References](#references)\n\n## Getting Started\n\n### Prerequisites\n+ .NET Framework 4.6.1\n+ Visual Studio 2019 Community\n+ NUnit Framework 3.13+\n\nMake sure that all unit test cases are passed before using the library.\n\n#### Installing NUnit **(Important : Windows Only)**\n\nFor windows users , NUnitTestAdapter have to be installed before you can run the test cases succcessfully.\n\n1.  From Tools menu, use Library Package Manager and select Manage NuGet packages for solution.\n\n2.  In the left panel, select Online\n\n3.  Locate (search for) NUnit 3.0 Test Adapter in the center panel and highlight it\n\n4.  Click install, and select existing project ApiSecuritySolution to add the adapter.\n\n\n### Using the QueryData and FormData Class\nThe ApiUtilLib Library provide the utility class QueryData to construct request Query String and Form Data.\n\n#### Generate QueryString\n```\n    var queryData = new QueryData();\n\n    queryData.Add(\"clientId\", \"1256-1231-4598\");\n    queryData.Add(\"accountStatus\", \"active\");\n    queryData.Add(\"txnDate\", \"2017-09-29\");\n\n    string queryString = queryData.ToString();\n\n    string baseUrl = string.Format(\"https://example.com/resource{0}\", queryString);\n    // https://example.com/resource?clientId=1256-1231-4598\u0026accountStatus=active\u0026txnDate=2017-09-29\n```\n\n#### Generate FormData\n```\n    var formData = new FormData();\n\n    formData.Add(\"phoneNo\", \"+1 1234 4567 890\");\n    formData.Add(\"street\", \"Hellowood Street\");\n    formData.Add(\"state\", \"AP\");\n\n    string formData = formData.ToString();\n    // phoneNo=%2B1+1234+4567+890\u0026street=Hellowood+Street\u0026state=AP\n```\n\n**NOTE** \n\nFor **formData** parameter used for Signature generation, the key value parameters **do not** need to be URL encoded, \nWhen you use this client library method **ApiAuthorization.HttpRequest**, it will do the url-encoding during the HTTP call\n\n### How to Generate L1 Authorization Header\n```\npublic void L1Sample()\n{\n    var URL = \"https://{gatewayName}.api.gov.sg/api/v1/resource\";\n    var APP_NAME = \"{appName}\";\n    var APP_SECRET = \"{appSecret}\";\n\n    // prepare form data\n    var formData = new FormData();\n    formData.Add(\"q\", \"how to validate signature in pdf\");\n    formData.Add(\"ei\", \"yAr8YLmwCM_Fz7sPsKmLoAU\");\n\n    var authParam = new AuthParam()\n    {\n        url = new Uri($\"{URL}\"),\n        httpMethod = HttpMethod.POST,\n\n        appName = APP_NAME,\n        appSecret = APP_SECRET,\n\n        formData = formData\n    };\n\n    // get the authorization token for L1\n    var authToken = ApiAuthorization.TokenV2(authParam);\n\n    Console.WriteLine($\"\\n\u003e\u003e\u003e BaseString :: '{authToken.BaseString}'\u003c\u003c\u003c\");\n    Console.WriteLine($\"\\n\u003e\u003e\u003e Authorization Token :: '{authToken.Token}'\u003c\u003c\u003c\");\n\n    // make api call with authToken.Token\n}\n```\n\n### Supported Private Key File Type\n1. .pem/.key - pkcs#1 base64 encoded text file\n2. .pem/.key - pkcs#8 base64 encoded text file\n3. .p12/.pfx - pkcs#12 key store\n\n### How to Generate L2 Authorization Header\n```\npublic void L2Sample()\n{\n    var URL = \"https://{gatewayName}.api.gov.sg/api/v1/resource\";\n    var APP_NAME = \"{appName}\";\n    var PRIVATE_KEY_FILE_NAME = \"privateKey.key\";\n    var PRIVATE_KEY_PASSPHRASE = \"{passphrase}\";\n\n    // get the private key from pem file (in pkcs1 format)\n    var privateKey = ApiAuthorization.GetPrivateKey(PRIVATE_KEY_FILE_NAME, PRIVATE_KEY_PASSPHRASE);\n\n    // prepare queryString\n    var queryData = new QueryData();\n    queryData.Add(\"view\", \"net-5.0\");\n    queryData.Add(\"system\", \"C# sample code\");\n\n    // get url safe querystring from ToString()\n    Console.WriteLine($\"\u003e\u003e\u003e Query String \u003e\u003e\u003e{queryData.ToString()}\u003c\u003c\u003c\");\n\n    // prepare form data\n    var formData = new FormData();\n    formData.Add(\"name\", \"peter pan\");\n    formData.Add(\"age\", \"12\");\n\n    var authParam = new AuthParam()\n    {\n        url = new Uri($\"{URL}{queryData.ToString()}\"),\n        httpMethod = HttpMethod.POST,\n\n        appName = APP_NAME,\n        privateKey = privateKey,\n\n        formData = formData\n    };\n\n    // get the authorization token for L1\n    var authToken = ApiAuthorization.TokenV2(authParam);\n\n    Console.WriteLine($\"\\n\u003e\u003e\u003e BaseString :: '{authToken.BaseString}'\u003c\u003c\u003c\");\n    Console.WriteLine($\"\\n\u003e\u003e\u003e Authorization Token :: '{authToken.Token}'\u003c\u003c\u003c\");\n\n    // make api call with authToken.Token\n}\n```\n\n### How to Generate L21 Authorization Header\n(for cross zone api from internet to intranet)\n```\npublic void L21Sample()\n{\n    var URL_WWW = \"https://{www_gatewayName}.api.gov.sg/api/v1/resource\";\n    var APP_NAME_WWW = \"www_appName\";\n    var PRIVATE_KEY_FILE_NAME = \"www_privateKey.key\");\n    var PRIVATE_KEY_PASSPHRASE = \"{password}\";\n\n    var URL_WOG = \"https://{wog_gatewayName}.api.gov.sg/api/v1/resource\";\n    var APP_NAME_WOG = \"{wog_AppName}\";\n    var APP_SECRET_WOG = \"{wog_appSecret}\";\n\n    // get the private key from pem file (in pkcs1 format)\n    var privateKey = ApiAuthorization.GetPrivateKey(PRIVATE_KEY_FILE_NAME, PRIVATE_KEY_PASSPHRASE);\n\n    // prepare queryString\n    var queryData = new QueryData();\n    queryData.Add(\"view\", \"net-5.0\");\n    queryData.Add(\"system\", \"C# sample code\");\n\n    // prepare form data\n    var formData = new FormData();\n    formData.Add(\"name\", \"peter pan\");\n    formData.Add(\"age\", \"12\");\n\n    // prepare the parameters\n    var authParam = new AuthParam()\n    {\n        url = new Uri($\"{URL_WWW}{queryData.ToString()}\"),\n        httpMethod = HttpMethod.POST,\n\n        appName = APP_NAME_WWW,\n        privateKey = privateKey,\n\n        formData = formData,\n\n        nextHop = new AuthParam()\n        {\n            url = new Uri($\"{URL_WOG}{queryData.ToString()}\"),\n\n            appName = APP_NAME_WOG,\n            appSecret = APP_SECRET_WOG\n        }\n    };\n\n    // get the authorization token for L21\n    var authToken = ApiAuthorization.TokenV2(authParam);\n\n    Console.WriteLine($\"\\n\u003e\u003e\u003e{tag}\u003c\u003c\u003c BaseString :: '{authToken.BaseString}'\u003c\u003c\u003c\");\n    Console.WriteLine($\"\\n\u003e\u003e\u003e{tag}\u003c\u003c\u003c Authorization Token :: '{authToken.Token}'\u003c\u003c\u003c\");\n\n    // make api call with authToken.Token\n}\n\n```\n\n### How to Generate L12 Authorization Header\n(for cross zone api from intranet to internet)\n```\npublic void L12Sample()\n{\n    var URL_WOG = \"https://{wog_gatewayName}.api.gov.sg/api/v1/reslource\";\n    var APP_NAME_WOG = \"{wog_appName}\";\n    var APP_SECRET_WOG = \"{wog_AppSecret}\";\n\n    var URL_WWW = \"https://{www_appName}.api.gov.sg/api/v1/resource\";\n    var APP_NAME_WWW = \"{www_AppName}\";\n    var PRIVATE_KEY_FILE_NAME = \"Certificates/www_privateKey.pkcs8\");\n    var PRIVATE_KEY_PASSPHRASE = \"{passphrase}\";\n\n    // get the private key from pem file (in pkcs8 format)\n    var privateKey = ApiAuthorization.GetPrivateKey(PRIVATE_KEY_FILE_NAME, PRIVATE_KEY_PASSPHRASE);\n\n    // prepare queryString\n    var queryData = new QueryData();\n    queryData.Add(\"view\", \"net-5.0\");\n    queryData.Add(\"system\", \"C# sample code\");\n\n    // prepare form data\n    var formData = new FormData();\n    formData.Add(\"name\", \"peter pan\");\n    formData.Add(\"age\", \"12\");\n\n    // prepare the token parameters\n    var authParam = new AuthParam()\n    {\n        url = new Uri($\"{URL_WOG}{queryData.ToString()}\"),\n        httpMethod = HttpMethod.POST,\n\n        appName = APP_NAME_WOG,\n        appSecret = APP_SECRET_WOG,\n\n        formData = formData,\n\n        nextHop = new AuthParam()\n        {\n            url = new Uri($\"{URL_WWW}{queryData.ToString()}\"),\n\n            appName = APP_NAME_WWW,\n            privateKey = privateKey,\n        }\n    };\n\n    // get the authorization token\n    var authToken = ApiAuthorization.TokenV2(authParam);\n\n    Console.WriteLine($\"\\n\u003e\u003e\u003e BaseString :: '{authToken.BaseString}'\u003c\u003c\u003c\");\n    Console.WriteLine($\"\\n\u003e\u003e\u003e Authorization Token :: '{authToken.Token}'\u003c\u003c\u003c\");\n\n    // make api call with authToken.Token\n}\n\n```\n\n## Release\n+ See [CHANGELOG.md](CHANGELOG.md).\n\n## Contributing\n+ For more information about contributing PRs and issues, see [CONTRIBUTING.md](https://github.com/GovTechSG/csharp-apex-api-security/blob/master/.github/CONTRIBUTING.md).\n\n## License\n[MIT LICENSE ](https://github.com/GovTechSG/csharp-apex-api-security/blob/master/LICENSE)\n\n## References\n+ [Akana API Consumer Security](http://docs.akana.com/ag/cm_policies/using_api_consumer_app_sec_policy.htm)\n+ [RSA and HMAC Request Signing Standard](http://tools.ietf.org/html/draft-cavage-http-signatures-05)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgovtechsg%2Fcsharp-apex-api-security","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgovtechsg%2Fcsharp-apex-api-security","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgovtechsg%2Fcsharp-apex-api-security/lists"}