Sometimes Wordpress isn’t that bad. When for instance you’re building a SEO optimized landing page for a custom made tool and you don’t want to develop everything your self. Secondly, Wordpress has thousands of plugins that can be very useful. In my case we are using Woocomerce with a subscription payment module, so that we can manage payed subscriptions for our tool and secondly we want to manage the user accounts inside Wordpress. This saves me lots of development hours and next to that I don’t have to build any maintenance tooling since that is already inplace in Wordpress. So first line support can be done by not-so-much technical people, in other words they won’t call for every problem :)
Overview
So in essence its very easy. We just have a user with a single set of credentials which he can use in both the SEO optimized page, lets say `example.com` and in the custom made tool lets say `app.example.com`. Using the [JWT Authentication for WP REST API](https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/) plugin of Wordpress we can login any user and get a JWT bearer token as response. The JWT Authentication plugin requires a JWT Auth Secret key which we can define and share with the `Azure Functions` backend. The functions backend then checks the validity of incoming Bearer token with the shared JWT Auth Secret key, making an additional call to Wordpress unnecessary. Its blazing fast.
But we are not there yet. We need some communication between the Functions backend and Wordpress on an application to application level. In my case I want to retrieve the available subscriptions and the active subscription for a user from Wordpress / Woocommerce. Subscriptions are the trial, starter, business and pro packs that users can buy and those “packs” enable the user some privileges inside my Angular tool. Since its app to app communication I can’t use a Bearer token, because thats user context bounded, and secondly the Woocommerce API requires an OAuth 1.0 authentication. It comes down to this. The Functions backend requires a Consumer key and a Consumer secret which need to be passed into a query string. Postman has excellent OAuth 1.0 support to test it out.
Keep in mind to not add the empty parameters to the signature. Woocommerce doesn’t support it.
So how does this look like in code. There are 2 parts that I want to share with you. Verifying a JWT Bearer token based on a JWT Auth Secret key and the OAuth 1 implementation with Woocommerce.
publicintValidateToken(HttpRequestMessage httpRequest) { try { // We need bearer authentication. if (httpRequest.Headers.Authorization.Scheme != "Bearer") { thrownew UnAuthorizedException(); }
// Get the token. string authToken = httpRequest.Headers.Authorization.Parameter; if (string.IsNullOrEmpty(authToken)) { thrownew UnAuthorizedException(); }
var tokenHandler = new JwtSecurityTokenHandler(); // Validate it. ClaimsPrincipal principal = tokenHandler.ValidateToken(authToken, tokenValidationParameters, out SecurityToken validatedToken); if (principal.Identity.IsAuthenticated) { // Check for a data claim. if (principal.HasClaim(x => x.Type == dataClaimType)) { Claim dataClaim = principal.Claims.FirstOrDefault(x => x.Type == dataClaimType); var userObj = JsonConvert.DeserializeObject<DataClaim>(dataClaim.Value); // With a user object. if (userObj != null && userObj.User != null) { return userObj.User.Id; } } } } catch { // Do nothing } thrownew UnAuthorizedException(); } }
Calling Woocommerce with OAuth 1.0
To interact with the Woocommerce API we need to implement the OAuth 1 flow. Its not used that much so you won’t find a lot of C# examples online. Here’s mine.
Inject a HttpClient, ConsumerKey and ConsumerSecret into the Constructor. Only set the OAuth properties that are actually used, remember the Postman option with including empty parameters. It was a pain in the ass to get in working but I tested this client with Wordpress 5.0.3 and Woocommerce 3.5.4.
var requestParameters = new List<string>(); foreach (string key in queryCollection) { requestParameters.Add($"{key}={queryCollection[key]}"); } // We need to sign a base string. string otherBase = GetSignatureBaseString(HttpMethod.Get.ToString(), "https://www.example.com/wp-json/wc/v1/subscriptions", requestParameters); var otherSignature = GetSignature(otherBase, consumerSecret);
// Add that signature to the query parameters. queryCollection["oauth_signature"] = otherSignature; string finalQueryString = queryCollection.ToString();
// And actually perform the request. var finalUri = new Uri("https://www.example.com/wp-json/wc/v1/subscriptions?" + finalQueryString, UriKind.Absolute); HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, finalUri); var response = await Client.SendAsync(httpRequestMessage); response.EnsureSuccessStatusCode(); returnawait response.Content.ReadAsAsync<Subscription[]>(); }
privatestringGetNonce() { var nonce = rand.Next(1000000000); return nonce.ToString(); }
privatestringGetTimeStamp() { var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); }
privatestringGetSignature(string signatureBaseString, string consumerSecret, string tokenSecret = null) { var hmacsha1 = new HMACSHA1();