Hello beautiful readers! Glad to see you again so soon. Today I’d like to share my findings about cookie authentication and our AngularJS WordPress theme. I’ll show you how exactly to get the cookie authentication working with the theme, and we’ll create a simple AngularJS custom directive to display the user name if she/he is logged in.
What I’ll be showing you in this post I actually spent over two months to figure that out (duh!). Eventually to my surprise that cookie authentication is quite simple when we are just building WordPress themes or plugins.
I was blind to the WP API documentation which have stated everything a developer need to know about cookie authentication and WP API, but once I sorted things out, it can’t be even more clear. So I highly recommend anyone who’s interested in this topic, be sure to check the docs out (as much more times as you need)!
If you’re new here, I started this Building Themes With AngularJS and WP REST API series since last November. In last tutorial I talked about how to upgrade the theme to work with WP API v2, you should download the latest project files from the GitHub repo. Now I’m ready if you are, let me start by introducing you how the cookie authentication works in WordPress.
Cookie authentication in WordPress
When we log in to the WordPress dashboard, this action will trigger the wp_signon()
, which then uses the wp_authenticate()
to check our login information (username and password). If they are validated, the wp_set_auth_cookie()
will be invoked that various authentication cookies will be set.
So every time when functions like get_current_user_id()
or wp_get_current_user()
are used to check if there’s a logged in user visiting a WordPress site, all validation functions hook to determine_current_user
filter will be applied, including wp_validate_auth_cookie()
.
As long as those cookies get validated, the authenticated user will be granted permissions to perform certain actions in WordPress core, themes or plugins. Take WP API for instance, a logged in user can access his own basic account information by visiting the route wp-json/wp/v2/users/me
, and get detailed information from route wp-json/wp/v2/users/[HIS-OWN-ID]?context=edit
.
There’s a key point I’d like to reminder you again that, this project (the AngularJS theme we’re building) is still a standard WordPress theme. That said when a logged in user makes requests with WP API in our theme, he can pass permission checks automatically for routes like wp-json/wp/v2/users/me
.
But things won’t stop here because internet is a dangerous place, bad guys out there are trying to fool us with phishing links, so they can gain access to our WordPress site and make everything a mess.
Phishing links are a typical method that hackers use to perform malicious exploits called CSRF (Cross Site Request Forgery). Luckily WordPress has developed a standard technique to prevent users from getting exploited by CSRF, which is called nonces (numbers used once).
Nonces in WordPress
Though the name may imply, nonces actually can be used more than once in their lifetime. Long story short, nonces are used to validate if a request is intentionally made by the current logged in user. They are generated based on those authentication cookies and a time-dependent variable, that makes them dynamic and can’t be forged by a 3rd party website.
You must be familiar with URLs from your WordPress dashboard look like:
http://URL/wp-admin/post.php?post=POST-ID&action=trash&_wpnonce=NUMBERS-LETTERS
This is very crucial that without the nonce, any hacker can send you an email with the delete link (and a kitty photo to trick you to click). You might just delete your own post without notice.
Now we know nonces are very important, but how can we implement this technique in our AngularJS theme?
Nonces in our AngularJS theme
According to WP API documentation on cookie authentication (emphasis added):
For developers making manual Ajax requests, the nonce will need to be passed with each request. The API uses nonces with the action set to
wp_rest
. These can then be passed to the API via the_wp_rest_nonce
data parameter (either POST data or in the query for GET requests), or via theX-WP-Nonce
header.
Let’s take a closer look at the exactly function rest_cookie_check_error()
from WP API v2 beta-4:
This function is beautifully coded and very self explanatory. From line 32 to 37, WP API checks for two values – $_REQUEST['_wp_rest_nonce']
and $_SERVER['HTTP_X_WP_NONCE']
, if they don’t exist, WP API will set the current user to 0
and return true
(means no authentication error but it’s an unauthenticated request). Otherwise, the nonce will get verified and return an WP_Error
object.
So apparently now we have two approaches to pass the nonce:
- Passing it as another url parameter so the routes would be like:
wp-json/wp/v2/posts/ID?context=edit&_wp_rest_nonce=NONCE
. - Sending the nonce (named X-WP-Nonce) in the request headers with each API call.
The second approach sounds a bit more challenging, right? I encourage you to take this approach with me that you’ll learn an in-depth technique in AngularJS about passing values with each request. In our case, that’ll be the nonce.
I hope you are ready with the theme files from GitHub, just open your favorite text editor and let’s start with functions.php
.
Creating a custom directive to display the current user name
Step1: Adding the nonce to our theme
Just like how we passed the _partials
directory to our JavaScript, we do that again by adding a new property to myLocalized
object. We name it nonce
(you can change the name) and use wp_create_nonce()
to create the nonce with the action set to wp_rest
(you definitely can’t change that).
Step 2: New currentUser object and getCurrentUser function in WPService factory
In our WPService
factory, we add a new property currentUser
to WPService
object and set it to an empty object. We also create a new function getCurrentUser
that sends a request to wp-json/wp/v2/users/me
to get basic account information from WP API. If the request is successful, we’ll then assign the response to the currentUser
object.
Step 3: Sending the nonce in the request headers
To set the request headers in AngularJS, we’ll do it with the $httpProvider.interceptors
. The AngularJS documentation introduces interceptors as below (emphasis added):
For purposes of global error handling, authentication, or any kind of synchronous or asynchronous pre-processing of request or postprocessing of responses, it is desirable to be able to intercept requests before they are handed to the server and responses before they are handed over to the application code that initiated these requests.
The interceptors are service factories that are registered with the
$httpProvider
by adding them to the$httpProvider.interceptors
array. The factory is called and injected with dependencies (if specified) and returns the interceptor.
Now let’s add the interceptor service factory to the configuration block in our app. The following gist shows that we set the X-WP-Nonce
header to the nonce we’ve created whenever an API request is made (at line 12):
Step 4: Creating a custom directive to say hello to a logged in user
Creating a custom directive in AngularJS is very easy, you can go back to check out my previous tutorial about it again. The gist below shows that:
- We create a custom directive to “say hello”.
- We can use the directive with syntax like “
<say-hello>
” or “<div say-hello>
“. - We need to create a new template file
say-hello.html
in our_partials
directory. - In this custom directive, we’ll call
WPService.getCurrentUser()
function to update theWPService.currentUser
object.
In the template file say-hello.html
, we test if data.currentUser.id
is true
, if so, we display our hello message.
And lastly, we just add the custom directive <say-hello></say-hello
> to the beginning of main.html
, or any place we’d like to show the hello message. Boom! We’re done!
Cookie authentication, nonces and AngularJS $httpProvider.interceptors
Although we were going to talk about cookie authentication in this tutorial, we actually spent more time on figuring out how to work with WordPress nonces in our AngularJS scripts. You should get the idea that getting a WordPress theme authenticated with WP API is really simple and don’t really need to worry anything about the cookies as a matter of fact.
You can also take this tutorial as a warm-up if you’d like to build a standalone AngularJS app with WP API in the future. For example, you might be interested in trying some third party authentication methods like JWT Auth for your standalone app, in that case you’ll need to use $httpProvider.interceptors
to pass cookies and Bearer Token.
As always, you can download the final project files from the GitHub repository. I hope you enjoy the whole process as I do, or at least learn some new tricks to solve your own issues. Just email (yoren [at] 1fix.io), tweet me (@1fixdotio) or leave a comment below if you get any question regarding my tutorials.
See you soon in my next post!
Leave a Reply