DEV Community

David Woolf
David Woolf

Posted on • Originally published at indexforwp.com on

Generating WordPress Application Passwords for your third party apps

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
})
Enter fullscreen mode Exit fullscreen mode

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>"
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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://
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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) {
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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}`
Enter fullscreen mode Exit fullscreen mode

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

david_woolf image

Top comments (0)