On Core REST API Authentication

Having an API is well and good, but if there are no ways for third-party apps to actually authenticate and use the API, it’s not very useful.

Background

While the framework for the REST API was merged into WordPress Core with the 4.4 release, the only means of using any endpoints that currently require authentication are what is known as ‘cookie authentication’ — that is, piggybacking off of the authentication cookies (plus a nonce) that WordPress Core sets in the browser when you log in traditionally to your WordPress site.  Unfortunately, that leaves the REST API as little more useful than the legacy `admin-ajax.php` file.

Fortunately, there are several authentication methods being worked on at the moment, in plugin form, for consideration of merging in to Core.

I’m heading up one of them, called Application Passwords.  In short, it lets a user generate as many single-application passwords as desired — one for each phone, desktop app, or other integration desired — and later revoke any application password whenever desired without affecting other applications or the user’s normal authentication.  The passwords are then passed with each request as Basic Authentication, encoded in the header of each request, as per RFC2617.

The other plugin is OAuth 1.0a authentication (spec).  Most OAuth usage across the internet is actually OAuth 2.0 — however, OAuth 2.0 requires HTTPS on the server side.  Ordinarily for most hosted services, this is not a problem.  However, for a distributed platform like WordPress, this is untenable due to the majority of sites not supporting HTTPS.  So an older, more complex specification — designed to not require HTTPS — had to be used.

For the record, I’m fully expecting to see an OAuth 2.0 plugin be built in the near future for use on sites that have a SSL certificate and support HTTPS.  However, that may not be very useful for app developers that want a ‘build once, run everywhere’ authentication method that will always be available.

Limiting Permissions

One of the discussions that came up with regard to Application Passwords is whether a REST API request that uses Application Password authentication should be able to modify Application Password endpoints.

Now, this is a very interesting question, and it can lead to many more questions — such as if an Application Password shouldn’t be usable to create or delete other Application Passwords, whether they should be allowed to do other user-administrative tasks (providing the relevant user has those permissions).  After all, if we’re preventing them from making a new Application Password, but they can just go and change the user’s actual password or email address, it’s a rather silly restriction.

So, there are several possiblilities.

First, you can just say “Any ways in to your account give full access to everything your account can do.  Be careful what applications and websites you give access to.” — the most basic, relatively easy to understand way.  Honestly, this is my preference.

Secondly, when creating a new Application Password or connecting a new client via oAuth, you could do something like … selecting what ‘role’ you’d like to give that connection.  For example, if your normal user account as an Administrator, but you’re connecting an app that’s intended just for writing blog posts, you may want to downscale your role for that authentication key to either an Author or perhaps an Editor.  An advantage to this is that it would be more cross-API — that is, it would work just as well with the legacy XML-RPC API, as with the new REST API.

This ‘role restriction’ method may be somewhat fragile, as it would need to only filter `current_user_can` and `user_can` — but only when checking the current user’s ID.  However, that may goof up some cron tasks that may run on the same request as the REST API request or other incendtal things.

Thirdly, we could do something REST API specific — either whitelist or blacklist REST API endpoints based on authentication key.  So, when either creating a new Application Password or authorizing a new OAuth connection, you would set rules as to what endpoints it can be used to hit.  Perhaps you’d want to allow all `wp/v2` namespaced endpoints, but no endpoints added by plugins to custom namespaces.  Or you want to only allow it to access core `posts` and `taxonomies` endpoints.  Or even something like allowing it to access anything but `plugins`, `themes`, `users`, or `options` endpoints.

The downside of this is that it won’t work with the legacy XML-RPC API and the user interface for it would likely be far more confusing for users.  It also could get problematic as permissions may vary for who can read `options` endpoints and who can write to them — or the like.  So then it may further complicate to allowing GET requests but not POST, PUT, DELETE requests to certain endpoints.

Your Thoughts?

In the end, I’m not sure what the best path forward is.  Maybe I’ve missed something.  But I am confident that we need to start paying more attention to authentication and permissions for the forthcoming REST API.  If you have any thoughts or remarks, please leave them in the comments.