Using OAuth 1.0 with the WordPress API & Custom Endpoints

This very long article covers setting up OAuth 1.0 to work with the core version of the WordPress API.

We will be generating client keys, oauth tokens, a custom endpoint and allowing access to our API only from those whom we have manually authenticated via OAuth.

Before we begin, I have 2 local installs of WordPress:

http://wp-api-main/

This is our main API website that our client will make requests to.

http://wp-api-client/

This is our client website that will make requests to the API website.

I have listed quite a few resources that I used to put together this tutorial at the bottom of the article. In some cases, I’ve just copied the code or steps. If you get stuck or want more info, I highly encourage you to read those resources. They will definitely be worth your time!

Get some coffee and let’s begin!

Test to make sure you can connect to the API.

Add the following code to your plugin on your client site.

Change the $url value to match the URL of the API site’s URL. So it will be something like http://example.com/wp-json

Mine is installed on my local machine that’s why the URL is http://wp-api-main/wp-json

Then create a new page and add this shortcode to the page [test_api_connection]

Open the page and you should see content like this:

Array
(
    [name] => WP-API Main
    [description] => Just another WordPress site
    [url] => http://wp-api-main
    [home] => http://wp-api-main
    [namespaces] => Array
        (
            [0] => oembed/1.0
            [1] => wp/v2
        )

    [authentication] => Array
        (
        )

    [routes] => Array
        (
            [/] => Array
                (
                    [namespace] => 
                    [methods] => Array
                        (
                            [0] => GET
                        )

                    [endpoints] => Array
                        (
                            [0] => Array
                                (
                                    [methods] => Array
                                        (
                                            [0] => GET
                                        )
// ...

Here’s what mine looks like:

The thing to notice is that the [authentication] is an empty array. Let’s change that part.

Now go to your main API site and install and activate the “WordPress REST API – OAuth 1.0a Server” plugin.

Once installed and activated, go to Users > Applications and click the [Add New] button.

On the “Add Application” page you will fill in some values. “Consumer Name” and “Description” can be whatever you wish. Just put something that makes sense.

I’m not sure what the Callback does at this time so I just inserted something like “http://wp-api-main/auth/success”.

After you have filled in all 3 fields, click the [Add Consumer] button.

Now you will see that the Client has a Client Key and Client Secret under the “OAuth Credentials” section.

Copy those for later.

Client Key (consumer_key):

CUQVVujOraZd

Client Secret (consumer_secret):

dcsgQT9B99f2bMSj2IWwMpbmr9dZFE0wzLCK4sZue60jZ9v9

Now if you go back to the new page you created on your Client site which has the shortcode, the [authentication] array should have some values in it.

Now we need to hook up these keys with our client so that our client can then make subsequent authenticated API requests to our API site.

The details behind this process are complicated and covered in detail in some of the resource links I share at the bottom of this article especially on nobil.cc.

The method I found the easiest to use the above keys is with an app like Postman or Paw. Postman is free and also has a Chrome extension if you aren’t on a Mac. I’ll use Postman in this tutorial because it’s free.

For these next steps, I relied heavily on nobil.cc. It contains more background on this process. Definitely worth the read!

If you have questions about these next few steps, check that article, too.

Open the Postman app.

In the “Get” request URL field enter the URL of the main API website’s /oauth1/request path. I have entered

http://wp-api-main/oauth1/request

Under Authorization Type, choose OAuth 1.0

Enter the Consumer Key (ie. the Client Key) and Consumer Secret (ie. the Client Secret).

Click the [Update Request] button. This will automatically fill in the timestamp field and the Nonce field.

Your request URL will have been update to something like this:

http://wp-api-main/oauth1/request?oauth_consumer_key=CUQVVujOraZd&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1481140823&oauth_nonce=vRxe3poywrw&oauth_version=1.0&oauth_signature=csft+J7hOAR97WhE6nZoRFhUfZs=

Then click the [Send] button.

Scroll down to see the response. You should see something like this:

oauth_token=OXjySsfBdsbWa04BMFAJy6ox&oauth_token_secret=8O20H7lyZ2s0vaGwnF4QrkdNt26iFXbpRsoigMFiwylwgqLz&oauth_callback_confirmed=true

Save that string somewhere. We will need these 2 initial OAuth tokens:

oauth_token

OXjySsfBdsbWa04BMFAJy6ox

oauth_token_secret

8O20H7lyZ2s0vaGwnF4QrkdNt26iFXbpRsoigMFiwylwgqLz

Next, we will use the “oauth_token” value we just got and construct a URL like this (on our Main API site):

http://wp-api-main/oauth1/authorize?oauth_token=OXjySsfBdsbWa04BMFAJy6ox

Load the URL in your browser.

You will get a login-type screen which has a message like “Howdy eric,
“Client API Connection” would like to connect to WP-API Main.”

Click the [Authorize] button.

The next screen will have a message like this: “Your verification token is PvHs1j8ol5FqVd4QPv0eGt9t

verification token

PvHs1j8ol5FqVd4QPv0eGt9t

Copy that token down… we’ll need that later, too!

The last step is to get our access token.

So in Postman, enter this URL into the request URL field:

http://wp-api-main/oauth1/access

This time you will need to fill in your:

  • Consumer Key
  • Consumer Secret
  • Token
  • Token Secret

Clicking the [Update Request] button will fill in the nonce and timestamp and your request URL will be transformed into something like this:

http://wp-api-main/oauth1/access?oauth_consumer_key=CUQVVujOraZd&oauth_token=OXjySsfBdsbWa04BMFAJy6ox&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1481141563&oauth_nonce=dJemNhotMRa&oauth_version=1.0&oauth_signature=08eCfNrGqovw4OF6P2uNrymLSdE=

Next click the [Params] button to the right of the request URL.

Add 1 new row to the params. Set the key to “oauth_verifier” and the value to “PvHs1j8ol5FqVd4QPv0eGt9t” (which is the value we got in the previous step.

Then click the [Send] button. Note that you may need to click the [Update Request] again and then click [Send].

After you scroll down you will see your new tokens.

oauth_token=LLnMXOF4aYlktf4X6DhAy0fr&oauth_token_secret=Ig5jaC1GmavfWrvUgN7w16LJT5yZT03DHRddmqpKM71us8Rn

oauth_token

LLnMXOF4aYlktf4X6DhAy0fr

oauth_token_secret

Ig5jaC1GmavfWrvUgN7w16LJT5yZT03DHRddmqpKM71us8Rn

You can now disregard your old oauth_token and oauth_token_secret tokens. You won’t need the old ones anymore. You only need these new ones. Additionally, you can disregard your oauth_verifier code as well. You shouldn’t need that code any more.

OK, we are done with Postman and we now have the necessary OAuth tokens we need in order to make an authenticated API request.

The only thing is, our main API site does not require authentication yet. So let’s force it to require authentication.

On your main API site, install the Disable Rest API plugin.

So now we have 2 plugins installed on our main API site:

  • WP REST API – OAuth 1.0a Server
  • Disable REST API

Let’s make sure our API now requires authentication. Go to the test page you created on your client site and load the page again.

You should now see a 401 “rest_cannot_access” message like this.

Excellent! I bet you’ve never been so happy to see a 401 message. 🙂

So, now that we have the keys to get around that restriction and authenticate, let’s do so.

But we’re not out of the woods yet… unfortunately, not even close.

The next bit of code mostly comes from this Sitepoint article. Please refer to that for more details. In our case, we will make a class that handles sending the proper headers to an API that requires authentication. Time to get more coffee… I’ll be here when you get back.

We are going to create a new shortcode so that we can add it to our page with the other shortcode.

Let’s first go to our page and modify our page so it looks like this:

<h2>test_api_connection</h2>
[test_api_connection]

<h2>test_api_oauth_connection</h2>
[test_api_oauth_connection]

Then we need to add a new shortcode to our plugin so we can start testing our OAuth connection.

Here’s our new shortcode:

A few things to take note of…

We added a $method variable and set it to ‘GET‘. That matches our wp_remote_get() call.

We added the various keys that we created to a $keys array.

Then we passed the $keys, $url and $method variables as parameters to our new OAuth_Authorization_Header() class. More on that in a second.

We get the $header value from the get_header() method and then added our authorization header array to a new $args array.

Lastly, we modified our call to wp_remote_get() by adding the $args array as the second parameter to the function.

The rest of the shortcode code is the same as our first one.

OK, so what about the new OAuth_Authorization_Header class?

Well, it’s a modified and simplified version of the class in the Sitepoint article which is itself a modified and simplified version of the code from a Twitter WordPress HTTP client. Love me some open source!

Here’s the basic OAuth_Authorization_Header class without documentation or checks to ensure all the required data is present… it’s a starting point. Be sure to validate the incoming arguments.

So now when you load the page with your shortcodes on your client site, you should have one ‘access denied’ message and one with a successful response.

The last thing I want to do is set up a custom endpoint on my API site and make that custom endpoint protected. Currently, all of our endpoints are private because we installed the Disable REST API plugin. But what if you just want a single custom endpoint to be private, not all endpoints?

Here’s how we can do that.

First, disable the Disable REST API plugin on your main API site.

After you do that, now both your shortcodes on your client site should load a successful response like this:

Next, create a custom plugin on your main API site and add the following code to your plugin:

Basically, this creates a new endpoint and returns an array if successfully called.

Let’s tweak our URLs in our client plugin:

In the client plugins we have this:

$url = 'http://wp-api-main/wp-json';

Let’s change that to this to make a request to a specific endpoint:

$url = 'http://wp-api-main/wp-json/myapiplugin/v2/greeting';

Be sure to change the $url variable in BOTH shortcodes.

Then refresh the page on your client site with the shortcodes. You should now see 2 successful responses.

Perfect! Now, let’s make that new endpoint private so only authenticated clients can access it.

Change the Main API plugin to this:

You see we have added a new item to array in the third parameter of the call to register_rest_route(). We have added:

'permission_callback' => 'myapiplugin_permission_callback',

Then we added a new function to our plugin that returns ‘true‘ if the current user can update core WordPress or false if the user can not. Who is this user that “current_user_can” is referring to? That user is our client who we have granted permissions to through the OAuth key exchange (back in the Postman section of this article).

So now that we have added this new authentication code to our plugin, let’s go back to our client shortcode page and reload that page.

Now you should see 1 access denied message and one success message.

And now you have successfully set up OAuth1 with your WordPress API so that a client that you have explicitly granted access to can call a private endpoint that you have set up.

Resources

Here are some of the articles I referenced when putting my article together. They were a huge help so if you are looking for more information about some of these steps, do check these out:

Create your own WordPress shortcode for Permalinks

I cringe every time I see a link in a blog post that is an absolute URL to other content on the same site. Here’s an example of what I mean:

In that example post you see a link to another page in my blog.

But what happens when you edit the slug of the post? The link will break.

Or what happens if you move your blog from /blog to /news? The link will break.

Or even worse, what happens if you change the domain where the content is hosted from http://www.mysite.com to http://blog.mysite.com? The link will break.

That’s why I cringe every time I see a link with an absolute URL to another page on the same site.

What’s the solution? Shortcodes.

Here’s an example of how to programmatically add links to your posts without being susceptible to the problems I mentioned above. The following code can be added to your theme’s functions.php file or to a custom plugin you might have.

After you add that code to your site, here’s how you can use it when writing a blog post or page.

To get the link to another post on your site all you need is the ID of the post you want to link to. Then in your post you would do something like this:

Now my link’s URL will be generated from the database and no matter how much we edit the other post’s slug or path, the correct URL will always appear in this link.

What if you want to avoid creating the <a href="">...</a> HTML code? That’s easy. Just do this:

Now when the post is rendered, the <a> tag will automatically be created and the title of the post will show up.

If you want to control the title of the link, you can do this:

Let me provide one last example to clear up any confusion… Let’s say you wrote a post on your blog. The post you wrote is titled Hello, World!, it has a slug of hello-world and the post has the ID of 33.

Here’s what the shortcode would look like in your posts and what would be returned:

Hope this helps future-proof the links in your blog posts.

How we used Advanced Custom Fields in Redesign

In my recent post about the plugins we used in the redesign of Datafeedr I mentioned I would go over how we used them.

The first one is Advanced Custom Fields. While you can do everything that this plugin does without using it, ACF sure helps to clean up the ‘add post’ interface as well as makes adding data to the built-in custom fields much easier and faster.

For example, when adding a new feature to our Features page, we needed fields to insert screenshots (image + description) and video IDs (IDs + description).

For the feature “Shortcodes“, we added 2 screenshots as well as 2 videos. Here’s what that looks like on the ‘add post page’:

datafeedr-advanced-custom-fields

Now it’s easy and understandable what type of data goes into each field.

To make the process of adding multiple screenshots and videos to a single post easier, we are using the Add-On Repeater Field to make life even easier. It’s not necessary but it’s cheap and worth it.

We used ACF for nearly every custom post type required for the new site. We have fields to add javascript to some pages but not others, fields for screenshots and videos and even fields to remove menus from specific pages of the site.

They also provide a much better alternative to get_post_meta() and that is get_field().

If you are the type to use the built-in custom fields in your WordPress Posts or Pages or custom post types, I would highly recommend checking out ACF.

New Ads Plugin – Beta Testers Wanted

We’ve rewritten our old Random Ads / Rotating Ads plugin. Those old plugins can be found here:

http://wordpress.org/extend/plugins/datafeedr-ads/
http://wordpress.org/extend/plugins/random-ads/

The new plugin has the following features:

– set impression limit (ad doesn’t get displayed after X number of impressions)

– set start date (date ad should not appear before)

– set end date (date ad should not appear after)

– has shortcode for use in posts, page and widgets

– has PHP code for use in template files

– works with caching plugins (tested with W3TC Enhanced Page Cache). Impressions are still counted and ads are ordered randomly even if you have caching enabled. (Doesn’t work if your site’s visitor has JavaScript disabled in their browser.)

– Add any type of ad.

– Set up groups for your ads to control where they display.

– Turn ON/OFF impression counting when admins view pages.

So far, no documentation. Use at your own risk. Hopefully set up is straightforward but videos and docs to follow.

Thanks for testing!

UPDATE 2013-03-18 11:32:36

We’ve officially released the plugin. Read more here: http://www.datafeedr.com/dfads/

Dynamically add link to WordPress menu based on user’s logged in status

In the recent redesign I wanted to modify the main menu (the horizontal menu that appears at the top of every page) to show a different menu item at the end of the menu based on the user’s logged in status.

To show you what I mean, here’s what the menu is supposed to look like when not logged in:

guest

And here’s what the menu was supposed to look like when a user was logged in:

loggedin

Due to some issues with W3 Total Cache and the fact that our logged in users were not logged in through WordPress (rather they are logged in through our Amember software), I was unable to get what I wanted while still caching pages. However, if you are simply relying on WordPress’s login system (and you probably are), this method will work. As a side note, fragment caching did not help solve the issue.

First, you need to make sure you have a menu configured under Appearance > Menus and that your menu is set to Primary Navigation.

menu

Next is just a matter of adding a little code to your theme’s functions.php file. Here’s a working example for the Twenty Twelve theme (be sure to exclude the opening php tags:

After you add that to your theme’s functions.php file and refresh your page, you should notice a new link appended to your Primary Navigation menu and that the link dynamically changes based on the user’s logged in status.

Plugins are good for you, but only in moderation

In the recent redesign of Datafeedr we choose 9 plugins (including 1 custom plugin) to build the new site. I don’t like to build sites using too many plugins. The more plugins that you activate the slower your site will potentially run. Also, the more plugins you have the more maintenance and updates you have to do. However the biggest reason I don’t install too many plugins is out of fear that those plugins won’t survive the next (minor or major) release of WordPress or will be abandoned/neglected by the plugin authors. I don’t hold that against the plugin developers. The plugins are free. Their time is expensive. Things change. Interests shift. Life happens.

I wanted to share the 9 plugins we used to build Datafeedr:

Over the next few weeks I’ll post about some of these plugins, what I like about them and in some cases how I tweaked them to suite our needs.