com.tmobile.oss.security.taap.poptoken.builder
1.0.10
dotnet add package com.tmobile.oss.security.taap.poptoken.builder --version 1.0.10
NuGet\Install-Package com.tmobile.oss.security.taap.poptoken.builder -Version 1.0.10
<PackageReference Include="com.tmobile.oss.security.taap.poptoken.builder" Version="1.0.10" />
paket add com.tmobile.oss.security.taap.poptoken.builder --version 1.0.10
#r "nuget: com.tmobile.oss.security.taap.poptoken.builder, 1.0.10"
// Install com.tmobile.oss.security.taap.poptoken.builder as a Cake Addin #addin nuget:?package=com.tmobile.oss.security.taap.poptoken.builder&version=1.0.10 // Install com.tmobile.oss.security.taap.poptoken.builder as a Cake Tool #tool nuget:?package=com.tmobile.oss.security.taap.poptoken.builder&version=1.0.10
Proof of Possession (PoP) Token – C# version
Source Repository
Setup
Add com.tmobile.oss.security.taap.poptoken.builder 1.0.10 component from NuGet.org to your .NET Core 3.1 (or greater) Project https://www.nuget.org/packages/com.tmobile.oss.security.taap.poptoken.builder/
Using OpenSSL, create non-encrypted RSA private and public keys in PKCS8 format
// # Create a 2048 bit Private RSA key in PKCS1 format
openssl genrsa -out private-key-pkcs1.pem 2048
//# Convert the Private RSA key to PKCS8 format.
openssl pkcs8 -topk8 -inform PEM -in private-key-pkcs1.pem -outform PEM -nocrypt -out private-key-pkcs8.pem
//# Create a Public RSA key in PKCS8 format
openssl rsa -in private-key-pkcs8.pem -outform PEM -pubout -out public-key.pem
// private-key-pkcs8.pem
// public-key.pem
- Use private key to generate PopToken (see code below)
- Use public key on Apigee side to validate PopToken
__C# Console Sample Code __
This sample C# code shows how to get oAuth2 access token using a PopToken header "X-Authorization"
using com.tmobile.oss.security.taap.poptoken.builder;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Net.Http.Headers;
// Setup initial vars
var privateKeyPemRsa = File.ReadAllText("rsa_private.pem");
var oauthClientKey = "<MyKey>";
var oauthClientSecret = "<MySecret>";
var userIdPasswordBytes = Encoding.UTF8.GetBytes($"{oauthClientKey}:{oauthClientSecret}");
var authorization = $"Basic {Convert.ToBase64String(userIdPasswordBytes)}";
var issuer = oauthClientKey;
var audience = oauthClientKey;
var httpTimeoutMilliseconds = 30000; // 30 secs
var baseUri = new Uri("https://api.yourdomain.com");
var oauth2QueryParam = "/oauth2/v6/tokens";
var apiQueryString = "/entity/v1/controller/action";
var apiPostBody = "{\"column1\": \"value2\"}";
// Get oAuth2 Token using PopToken
// Create PopToken for /oauth2/v6/tokens POST call (with no Body)
var keyValuePairDictionary1 = new Dictionary<string, string>
{
{ PopEhtsKeyEnum.HttpMethod.GetDescription(), PopEhtsKeyEnum.Post.GetDescription() },
{ PopEhtsKeyEnum.Uri.GetDescription(), oauth2QueryParam },
{ PopEhtsKeyEnum.CacheControl.GetDescription(), PopEhtsKeyEnum.NoCache.GetDescription() },
{ PopEhtsKeyEnum.ContentType.GetDescription(), PopEhtsKeyEnum.ApplicationJsonCharsetUtf8.GetDescription() },
{ PopEhtsKeyEnum.Authorization.GetDescription(), authorization }
};
var hashMapKeyValuePair = HashMapKeyValuePair.Set<string, string>(keyValuePairDictionary1);
var popTokenBuilder = new PopTokenBuilder(audience, issuer);
var popToken = popTokenBuilder.SetEhtsKeyValueMap(hashMapKeyValuePair)
.SignWith(privateKeyPemRsa)
.Build();
// Get the oAuth2 access (bearer) token using X-Authorization (PopToken) header
var oHttpClient = new HttpClient();
oHttpClient.Timeout = TimeSpan.FromMilliseconds(httpTimeoutMilliseconds);
oHttpClient.BaseAddress = baseUri;
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, oauth2QueryParam);
httpRequestMessage.Headers.Add(PopEhtsKeyEnum.CacheControl.GetDescription(), PopEhtsKeyEnum.NoCache.GetDescription());
httpRequestMessage.Headers.Add(PopEhtsKeyEnum.Authorization.GetDescription(), authorization);
httpRequestMessage.Headers.Add("X-Authorization", popToken);
httpRequestMessage.Content = new StringContent("{}", Encoding.UTF8, PopEhtsKeyEnum.ApplicationJson.GetDescription());
var response = await oHttpClient.SendAsync(httpRequestMessage);
var json = await response.Content.ReadAsStringAsync();
var authTokenResponse = JsonSerializer.Deserialize<AuthTokenResponse>(json);
var acccessToken = authTokenResponse.AccessToken;
// Now call main API using above bearer token (using a new PoPToken)
// Create new PoPToken for API POST call (with Body)
var keyValuePairDictionary2 = new Dictionary<string, string>
{
{ PopEhtsKeyEnum.HttpMethod.GetDescription(), PopEhtsKeyEnum.Post.GetDescription() },
{ PopEhtsKeyEnum.Uri.GetDescription(), apiQueryString },
{ PopEhtsKeyEnum.ContentType.GetDescription(), PopEhtsKeyEnum.ApplicationJsonCharsetUtf8.GetDescription() },
{ "Accept", PopEhtsKeyEnum.ApplicationJson.GetDescription() },
{ PopEhtsKeyEnum.Authorization.GetDescription(), "Bearer " + acccessToken },
{ PopEhtsKeyEnum.Body.GetDescription(), apiPostBody }
};
var hashMapKeyValuePair2 = HashMapKeyValuePair.Set<string, string>(keyValuePairDictionary2);
var popTokenBuilder2 = new PopTokenBuilder(audience, issuer);
var popToken2 = popTokenBuilder2.SetEhtsKeyValueMap(hashMapKeyValuePair2)
.SignWith(privateKeyPemRsa)
.Build();
// Call main API using above Bearer Token and new PopToken
var oHttpClient2 = new HttpClient();
oHttpClient2.Timeout = TimeSpan.FromMilliseconds(httpTimeoutMilliseconds);
oHttpClient2.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(PopEhtsKeyEnum.ApplicationJson.GetDescription()));
oHttpClient2.DefaultRequestHeaders.Add(PopEhtsKeyEnum.CacheControl.GetDescription(), PopEhtsKeyEnum.NoCache.GetDescription());
oHttpClient2.BaseAddress = baseUri;
var httpRequestMessage2 = new HttpRequestMessage(HttpMethod.Post, apiQueryString);
httpRequestMessage2.Headers.Add(PopEhtsKeyEnum.Authorization.GetDescription(), "Bearer " + acccessToken);
httpRequestMessage2.Content = new StringContent(apiPostBody, Encoding.UTF8, PopEhtsKeyEnum.ApplicationJson.GetDescription());
httpRequestMessage2.Headers.Add("X-Authorization", popToken2);
var response2 = await oHttpClient2.SendAsync(httpRequestMessage2);
var json2 = await response2.Content.ReadAsStringAsync();
To validate PopToken, see unit test code:
For ASP.NET MVC / WebApi
Use AddTransient when setting up the PopTokenBuilder injection in Startup.cs
// IPopTokenBuilder
services.AddTransient<IPopTokenBuilder>(_ =>
{
return new PopTokenBuilder(_audience, _issuer);
});
Known Issues:
When using RestSharp.RestClient() to obtain an oAuth2 access token, RestClient adds the "charset" string to the end of Content-Type. e.g. "application/json; charset=utf-8". This will cause a PopToken error if this extra string is not accounted for in the PopToken Ehts KeyValueMap. The work-around for RestClient is to use an "Accept" header, and then clear the parameters, then add any empty body.
var client = new RestClient(url);
client.Timeout = auth2TimeoutMilliseconds;
var request = new RestRequest(Method.POST);
request.AddHeader("Accept", PopEhtsKeyEnum.ApplicationJson.GetDescription());
request.Parameters.Clear();
request.AddParameter(PopEhtsKeyEnum.ApplicationJson.GetDescription(), "{}", ParameterType.RequestBody);
request.AddHeader(PopEhtsKeyEnum.Authorization.GetDescription(), authorization);
request.AddHeader("X-Authorization", popToken);
request.AddHeader(PopEhtsKeyEnum.CacheControl.GetDescription(), PopEhtsKeyEnum.NoCache.GetDescription());
IRestResponse response = client.Execute(request);
Even with this RestSharp.RestClient work-around, it is still recommend that you use “System.Net.Http.HttpClient” with HttpClientFactory, which solves sockets and stale DNS issues.
For more info, please read this article: https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Microsoft.IdentityModel.JsonWebTokens (>= 6.12.2)
- Microsoft.IdentityModel.Tokens (>= 6.12.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on com.tmobile.oss.security.taap.poptoken.builder:
Package | Downloads |
---|---|
com.tmobile.oss.security.taap.jwe
This component is for field level encryption. It will encrypt your PII data as a JWE token using a public RSA RS256 or EC P-256 key. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Update all NuGet packages to latest versions.
Updated component to use .NET Standzard 2.1.
Updated Builder to accept PEM or XML Key format.
Fix PEM file format issue.
Use "application/json", not "application/json; charset=utf-8"
Add constant: "application/json; charset=utf-8"
Add import RSA public / private keys and encrypted private key with password options