This is a digression from a series of posts discussing using a tool written in Lua to publishing posts on a WordPress blog.
- Part 1 showed how to use XML-RPC and
- Part 2 added file reading to make a minimal working utility.
- Part 3 added amenities and made the utility useful.
- Part 4 will switch to the REST API and OAuth
But before we can really get to Part 4, we need to delve into some of the mysteries of OAuth since it is the mechanism used by WordPress to get around many of the security issues that are implicit in using saved usernames and passwords.
Unfortunately, the improved security of OAuth comes at the price of ease of use. The old XML-RPC API generally required that a username and password be supplied in the body of each request. If the requests were not handled over a secure connection (using an
https: URL) then your password is available to anyone who is listening.
The solution that is becoming the accepted standard practice is to replace passwords with security tokens that in effect prove to the server that the client is authorized to make the request. While tokens could be stolen, their utility is limited because they are useful only for conversations with a specific server, and often about a specific resourse. On WordPress.com, tokens are generally limited to a single blog accessed by a single user, for example.
OAuth at WordPress.com is described by their OAuth2 Authentication page. Unfortunately that page is fairly opaque on a first reading. This post will attempt to clarify that document by attempting relate it to our WP CLI utilities.
Although I have only tested against WordPress.com hosted blogs while writing this post, everything should also work with self-hosted blogs that have the Jetpack plugin installed and correctly configured.
OAuth replaces a username and password that must be either entered manually or stored locally so that it is available every time you run the script, and which are transmitted to the server on every request. Entering a password manually swiftly becomes annoying, and the user will be tempted to make the password simpler and easier to type, which will reduce its strength and make the user’s blogs less secure. Which hints at the other problem. For users of the powerful, free, and popular WordPress.com blog hosting service, your are encouraged to have a single account that can own and be authorized (at various levels) at multiple blogs. So by requiring that the user tell our tool a username and password and allowing the tool to store that on her PC, we are actually letting the tool store information that potentially provides access to every blog the user can update rather than just the one she wants to post to.
OAuth is different. With OAuth, the tool asks the blog for permission to operate, and the user of the blog has to log in to WordPress and grant that permission. For each individual blog they want to update. If they change their mind, they can revoke that permission and the tool will no longer be able to make updates.
The tool itself need never know or store the password. In fact, it would be a bad idea for it even ask for the password. The tool is expected to launch the system web browser to perform the authorization, which will provide the tool a token it can store as evidence that the user authorized its use.
If you’ve used the mobile apps for facebook, flickr, or even WordPress, you’ve already seen OAuth in practice.
From a developer’s perspective, the work related to supporting OAuth in a client application can be roughly divided into tasks that must be done as part of writing the application, and tasks the application does when the user is using it.
Understand OAuth Client Workflow
Warning: From a security perspective, I am just some guy writing a blog on the internet. Please take the time to review security decisions for your own application, and please do hire security experts if you are handling any data more private or valuable than yesterday’s lunch menu. Furthermore, I may be wrong and security is an area where overconfidence is very prone to lead to lapses.
Due to the history of the OAuth specification itself, the current release of the specification is best thought of as a security framework. It provides a point of reference for terms of art and sequences of actions by the various interested parts of the system. Unfortunately it leaves a lot of decisions open to the implementation and there are likely ways to produce a fully compliant system that is less secure than just using passwords.
A key requirement is that secure connections be used for all transactions, with the corollary that all relevant certificates must be valid. In other words, you should always use
http:, and your implementation must be able to warn you about invalid certificates.
OAuth names three distinct parties to the security negotiation: The client application accesses a resource owned by a service through an API of the resource server.
There are some pre-conditions: The client is known to the service through a registration process when it was developed. The user is known to the service by some form of user registration and account process.
In the workflow we expect to use, the user will ask the service to authorize the client. The client can then use that authorization to act as the user until it expires.
Create and Register an Application
Before our client application can use OAuth, it must be known to the service, that is WordPress.com. To do that we need to create and register an application with WordPress. Once completed, this process gives us the information that must be coded in the application to identify our tool to WP. Naturally, you need to log in to your WordPress account to do this.
Note that all OAuth services require this step, and even if an application is designed to operate with more than one service, this step must be performed by the developer once for each service and the resulting service IDs must all be stored for use with their matching service providers.
In that form at WordPress.com, you provide a name and description of the application that will be shown to users. You need to provide URLs for a website for the application, and where to redirect after authorization is complete.
For this application make the Type be “Native” and not “Web” since that better describes the usage pattern of a CLI tool.
Once you’ve filled in the form, and then added additional information in the second page, you will be issued your OAuth2 identifiers for the application.
Warning: Keep the Client Secret string secret. With that string, someone can impersonate your application, and that could be bad.
This is the origin of the distinction between web and native application. Native applications are assumed to be accessible by an attacker for reverse engineering or even fully open source. So OAuth makes it possible to get an access token without needing to store the Client Secret in the client application at all. This is obviously the path we should take.
At any time you can view a list of your applications where you can access each to manage its settings, regenerate a lost secret, and even learn some statistics about its use in the wild.
Naturally we don’t want just anybody making posts to our blog. That is where the OAuth mechanism comes in to play.
Given that we have created and registered an application already, we now need to use the application’s OAuth identifiers to retrieve a token which will allow us to operate on the blog. This is a complex process behind the scenes, but it boils down to two major steps:
- Get an Authorization Grant: our Client ID and Redirect URI are exchanged for an authorization token. The user logs in to the authorization server (wordpress.com in this case) and affirms our access level as part of this process.
- Get an Access Token: our Client ID, Secret and authorization token are exchanged for an access token without user intervention.
For a native application workflow, these two steps are folded into one from our perspective. We exchange our Client ID and Redirect URI directly for an access token that has a short lifetime, but the user is required to take action at the WordPress.com website to allow this exchange.
We store the access token for use when actually making posts or taking other actions that require authentication. The token will expire, so we will also store enough information to enable us to ask the user to fix that when it happens, or for some styles of authorization, enough information for us to fix it without the user’s intervention.
The client asks the user for permission. This is done via a system provided web browser so that the user can log in to WordPress.com without fear that the client application is directly involved.
To do this, the client asks the system to fetch an url from the authorization endpoint. The URL to fetch is long due to the number of required parameters, so I’ve broken it up for display here.
https://public-api.wordpress.com/oauth2/authorize ?client_id=... &redirect_uri=... &response_type=... &blog=...
redirect_uri must match information in your application’s description as registered with wordpress.com. The client ID was assigned when you created the app, and the redirect URI is specified by you as part of the app profile.
blog is optional, and can be used to suggest that the app wants to be used with a particular blog. If not supplied, the user will be given a list of their blogs and be asked to select which one the authorization will apply to. Either way, the delivered token will permit access to only that one blog.
response_type is either
token, but for a native application the recommended type is
token which causes WordPress.com to do what they call Implicit OAuth and directly issue an access token. The
code response is an authorization token that must be exchanged along with the Client Secret to get the access token. Since that would require storing the Client Secret, that is not recommended for native applications.
The first page the user sees describes the application that is requesting access, using fields you filled out when you registered your application. You can see that here for
token and here for
code for the version of the WP Client Tools application that I registered for myself.
If the user wants to see what applications they have authorized and possibly revoke one, they can do that at the Security section of their personal account settings.
Both of the
authorize URLs I’ve given above will redirect to the same page at this blog, which is completely unaware of the extra information returned in the page URL. More on that in the next section.
Since we are using the Native App workflow, we will use the
token request type. After the user has granted permission, her browser will be redirected to the
redirect_uri, with additional information added after a
The application should be implemented in a way that permits this information to be automatically extracted and stored. In the URI quoted above, we can locate the following fields:
#access_token=tq5gXPd%24YZIIu%21D%40KBAv%21sdt%405Zdgy9i%5EJrMRkg3%24%23Sx%26X%25MlrmnRxgc%40Eyr%40uMT &expires_in=1209600 &token_type=bearer &site_id=73256621
(Note that the access token shown is already disabled, but it did come from a successful authorization session for this blog. I’m not quite foolish enough to publish an open token!)
The token has been URL encoded with
%xx hex notation. The expiration is given in seconds, and for WordPress.com is currently always 2 weeks. The token type will always be
bearer. The site ID is the unique serial number of the authorized blog.
For clients running in typical phone environments, it is often easy to register a temporary URI schema, and set the redirect URI to something like
myprivateauth://myapp/ and let the phone’s browser restart the application when the user is done by fetching that URL. For clients running in a PC, the smart option seems to be to make the redirect URI be something like
http://localhost:12345/myapp/ and start a very limited web server before sending the user off to give authorization. When his local browser redirects to that URL, the app’s internal web server can capture the token and display a page letting the user know that the authorization is complete.
Further Reading about OAuth
- OAuth 2 Simplified
- WordPress OAuth2 Authentication
- OAuth Standard
- Using OAuth 2.0 to Access Google APIs
There is no actual code in this post. The next obvious step is to write some.
The plan is to add an authorization tool to the collection of WP CLI utilities. It will launch the system web browser to get authorization, and will run a web server to catch the redirection. When redirected, it will write the token and related info down in a configuration file for use by the rest of the utilities.
Keep an eye open here for that installment “real soon now”!