In our Postman walkthrough, we went over how to generate application passwords for a single user and pass it with each REST request to handle authentication. For real world use, asking users to go login to their account, generate a password, and copy it back into another app is a lot of friction. Luckily we can create a workflow to make this easier.
Note: we’ll be using Javascript and PHP for all examples in this article
Getting started
First, we need to verify the specific WordPress installation supports application passwords and if so, what the authorization url is (we’ll use this later to automate some of the steps to create a password). Assuming we know the website URL, we just need to do a GET request to the website’s main REST endpoint (wp-json):
fetch('https://theory.local/wp-json')
.then(response => response.json())
.then(body => {
// check the authentication value here
})
Note: For these examples, I am using the Local app with SSL enabled. You must have an SSL connection to handle application password requests
Inside of our fetch statement, we’re requesting the wp-json
endpoint which will return the overall API structure of the site as a JSON object. Inside this object, we’re looking for the authentication
property. If it’s missing or empty, then we can’t do authentication on the site. If authentication is enabled, it will return an object that contains the authorization endpoint:
"authentication": {
"application-passwords": {
"endpoints": {
"authorization": "<https://theory.local/wp-admin/authorize-application.php>"
}
}
}
If you go to that url and login, you’ll see something like the following:
Without passing in some parameters, it functions just like the application password section when editing a user in the dashboard. Here are the parameters we can pass:
app_name (required): human readable name (you app name, etc)
app_id (optional, but recommended): UUID string
success_url (optional, but recommended): the url to send the user to if they approve the connection. Supports multiple protocols, EXCEPT for the non-secure http://
reject_url (optional): the url to send the user to if they reject the application. Supports multiple protocols, EXCEPT for the non-secure http://
The success URL will be appended with three parameters: site_url
, user_login
, and password
. Also, if you don’t pass a reject_url
value, it will go to the success_url
value and add ?success=false
(this might be preferred if you want to manage everything from one page).
Creating your own app authentication
To provide an example of creating an application password for your app to connect to WordPress, we’re going to create a simple, local HTML/PHP form that takes the user to another local WordPress instance, generates the password and passes it back.
Setting up our form
Our form will be pretty basic, just an input to enter the website URL and a submit button (I’ve omitted styling code to make this more concise):
<form
id="create-authentication-password"
action="/"
method="POST">
<h1>
Connect your site
</h1>
<label
for="website">
<strong>
Your Website URL
</strong>
<input
id="website"
type="url"
name="website"
placeholder="https://"
required
pattern="https://.*">
</label>
<input
type="submit"
value="Submit">
</form>
We’re using some newer technologies to quickly validate that the input is filled out and is a valid https url. Then we just have a standard submit button. Our form action is /
because that’s the page URL I have it on, and we’ll be using Javascript to send the form. Here is how the form looks (again, I have CSS classes added):
Using Javascript to submit the form
We’re going to use ES6 syntax, and to get started we want to listen for the form submission:
<script type="javascript">
document
.getElementById('create-authentication-password')
.addEventListener('submit', e => {
e.preventDefault()
// take action here...
})
</script>
Next, we want to grab our input value. We can create a new FormData
class, pass in our form and grab our input named website
:
<script type="javascript">
document
.getElementById('create-authentication-password')
.addEventListener('submit', e => {
e.preventDefault()
// NEW CODE
const data = new FormData(e.target)
const website = data.get('website')
})
</script>
Next, we want to do our GET request on wp-json
like we discussed initially:
<script type="javascript">
document
.getElementById('create-authentication-password')
.addEventListener('submit', e => {
e.preventDefault()
const data = new FormData(e.target)
const website = data.get('website')
// NEW CODE
fetch(`${website}/wp-json`)
.then(response => response.json())
.then(body => {
// do an action here
})
})
</script>
Finally, we’ll verify application support is available, grab the url to generate a new password, and pass in some parameters to redirect the user back:
<script type="javascript">
document
.getElementById('create-authentication-password')
.addEventListener('submit', e => {
e.preventDefault()
const data = new FormData(e.target)
const website = data.get('website')
fetch(`${website}/wp-json`)
.then(response => response.json())
.then(body => {
// NEW CODE
if('authentication' in body && body.authentication !== false) {
const root = body.authentication['application-passwords'].endpoints.authorization
const params = '?app_name=Sandbox Website&success_url=https://sandbox.local/success'
window.location = `${root}${body}`
}
})
})
</script>
Let’s go over the new code line by line. First, we check for support with Javascript’s key in object
code and ensure it’s not false:
if('authentication' in body && body.authentication !== false) {
Since the condition code will only fire if there is application password support, the rest of the code can setup the final url to go to:
const root = body.authentication['application-passwords'].endpoints.authorization
const params = '?app_name=Sandbox Website&success_url=https://sandbox.local/success'
Our root URL is the provided application password authorization URL from our fetch request. The params are a simply URL parameters string with our app name and success url (in production code, make sure to pass in an app_id).
Finally, we do a simple window.location
page send with our root and body:
window.location = `${root}${body}`
This code will take the user to the inputted website and, if they click “Yes, I approve of this connection”, the site url, username, and application password will be sent back as URL parameters (this is why using https:// is important to prevent someone capturing these values). On my success page, I output these values as an example, and here’s what they look like:
Wrap Up
That’s all you need to create a simplified application password flow for your users! This is a basic authentication system where you pass back the username and password using base64 encryption. You should also make sure you encrypt the values when storing them to prevent security issues. Happy coding!
Author
Top comments (0)