OAuth specification 2.0 is out there since 2012 but 1.0a version is still widely used. Atlassian’s Jira is for example such case. You wouldn’t find anything about 1-Legged OAuth in the documentation but the fact is, by now, Jira is still supporting this flow but referring to this wrongly as 2-Legged OAuth. Sadly there aren’t lot of .Net Core libraries which implements OAuth’s 1-Legged, as described in the The OAuth Bible. I implemented this functionality into oauth-dotnetcore library and will show you how this can be used to access Jira APIs.

Before the application can make a request against Jira you need to create RSA public / private key pair and register new application to allow 2-Legged OAuth and user impersonation through 2-Legged OAuth.

For the request self you will need to have Consumer Key and Consumer Secret which is actually a private key you generated before as a PEM format.

//Generate authorization header
OAuthRequest oauthRequest = OAuthRequest.ForProtectedResource("GET", "CONSUMER_KEY", "CONSUMER_SECRET", string.Empty, null, OAuthSignatureMethod.RsaSha1);
oauthRequest.RequestUrl = $"{baseUrl}{resource}?{queryLanguage}{searchOperator}{searchBy}{searchOperator}{searchValue}&user_id={userId}";
string authorizationHeader = oauthRequest.GetAuthorizationHeader();
//Make request
var httpClient = new HttpClient();
// authorizationHeader.Remove(0,6) => Remove "OAuth " from authorizationHeader to avoid to have invalid header
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("OAuth", authorizationHeader.Remove(0,6));
string result = await httpClient.GetStringAsync(oauthRequest.RequestUrl);
string formattedJson = JToken.Parse(result).ToString(Formatting.Indented);

What is really important here is to set accessToken which is actually oauth_token in term of specification to string.Empty as required in the specification, otherwise the signature and the header will be wrong.

You can store the key pairs safe in Windows Certificate Store and use the private key to sign the request. Only thing you need is to convert the RSA private key to PEM format.

private static string GetCertificatePrivateKeyAsPem(string certificateThumbprint, StoreLocation storeLocation)
{
	var certificationStore = new X509Store(storeLocation);
	certificationStore.Open(OpenFlags.ReadOnly);
	X509Certificate2Collection certificates = certificationStore.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);
	if (certificates.Count > 0) 
	{ 
		var certificate = certificates[0];
		var rsaPrivateKey = certificate.GetRSAPrivateKey();
		var privateRsaKey = DotNetUtilities.GetRsaKeyPair(rsaPrivateKey).Private;
		var memoryStream = new MemoryStream();
		using (TextWriter textWriter = new StreamWriter(memoryStream))
		{
			var pemWriter = new PemWriter(textWriter);
			pemWriter.WriteObject(privateRsaKey);
			textWriter.Flush();
			return System.Text.Encoding.UTF8.GetString(memoryStream.ToArray(), 0, (int) memoryStream .Length);
		}
	 }
	return null;
}

GetRsaKeyPair and PemWriter in the code below are in the Portable.BouncyCastle NuGet package.

This is how request may looks like.

GET /jira/rest/api/2/search?jql=assignee=anton.kalcik&user_id=anton.kalcik HTTP/1.1
Authorization: OAuth oauth_consumer_key="CONSUMER_KEY",oauth_nonce="tqjfjtxsatwftw8p",oauth_signature="NTIzZGY4MzVmZWY5ZWVmYjdkMGMzNGRmZDQ5ODVmNDRmYTI4MGRiNGIwNjIwNTE0MzQxMmY3MTRiNTZmODE3NgpkMWRjOTkzMzc5NjdlNmExMDNiM2M5NWQ5ZmJmN2FiNTJjODBjNDRjZDAwOWQ2NTgwZTczZTZiN2UyNDQ5ODY1CjkwY2U1M2EwYTMwNjc2MDE3NTI1YjUyNDhiMDAwYmI0YWE5MjJhOWRmNjE1YTUyNzJkMTU2YzQyNWMzZDMyNjMKNzc5N2U3NDg4ZDQxMjIzZTA3NTBkNDkyNmVmYmQ3YjgyMjI0YWQ3ODY4OGE0OGI4ODE5MTI4YjNiZmY1YTg4Yg==",oauth_signature_method="RSA-SHA1",oauth_timestamp="1557962068",oauth_token="",oauth_version="1.0"
Host: example.com

1 comment

  1. Hi Anton,
    thanks for this. This is pretty much the only article that brings some light into how to make OAuth request to Atlassian s…tuff I was able to find. Their documentation is just incomplete and misleading and one doesn’t have an idea how to put all the things together (especially in .NET when they have no example for it).

    Thanks for this mate!
    Vocko

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.