Mateusz Mysiak
Mateusz Mysiak

Reputation: 548

401 when trying to create a post in Wordpress API using Oauth 1.0

I'm trying to create a Wordpress post through Wordpress API v2, however the oauth 1.0 is throwing 401 at me when I do axios.post. When I do axios.get, everything's perfect and I get the result.

I can create or delete posts through Postman without a problem, but it configures itself automatically. It would be nice if I could copy the request somehow from postman and put it into axios code, but couldn't find this option.

I tried specifying the header for content-type as application/json like so:

headers: {
    'Content-Type': 'application/json'
}

as it was in Postman, but still no change.

I'm using a generator for Oauth signature and it's working in GET request as pointed out. https://www.npmjs.com/package/oauth-signature

Here's the code for the get and post requests:

getRequest = () => {
    const requestParams = { ...this.state.parameters }
    requestParams.oauth_nonce = this.generateNonce()
    requestParams.oauth_timestamp = new Date()
      .getTime()
      .toString()
      .slice(0,10)
    const encodedSignature = oauthSignature.generate(
      'GET',
      'http://localhost/wordpress-api/wp-json/wp/v2/posts/29',
      requestParams,
      this.state.consumerSecret,
      this.state.tokenSecret
    )

    axios({
      url: 'http://localhost/wordpress-api/wp-json/wp/v2/posts/29',
      method: 'get',
      auth: `
        OAuth oauth_consumer_key="${requestParams.oauth_consumer_key}",
        oauth_token="${requestParams.oauth_token}",
        oauth_signature_method="${requestParams.oauth_signature_method}",
        oauth_timestamp="${requestParams.oauth_timestamp}",
        oauth_nonce="${requestParams.oauth_nonce}",
        oauth_version="${requestParams.oauth_version}",
        oauth_signature="${encodedSignature}"
      `
    })
      .then(res => {
        this.setState({
          requestResponse: res
        })
      })
  }

postRequest = (e) => {
    e.preventDefault()

    const postData = {
      title: this.refs.title.value,
      status: 'publish',
      content: this.refs.content.value,
    }

    const requestParams = { ...this.state.parameters }
    requestParams.oauth_nonce = this.generateNonce()
    requestParams.oauth_timestamp = new Date()
      .getTime()
      .toString()
      .slice(0,10)
    const encodedSignature = oauthSignature.generate(
      'POST',
      'http://localhost/wordpress-api/wp-json/wp/v2/posts',
      requestParams,
      this.state.consumerSecret,
      this.state.tokenSecret
    )

    axios({
      url: 'http://localhost/wordpress-api/wp-json/wp/v2/posts',
      method: 'post',
      data: postData,
      auth: `
        OAuth oauth_consumer_key="${requestParams.oauth_consumer_key}",
        oauth_token="${requestParams.oauth_token}",
        oauth_signature_method="${requestParams.oauth_signature_method}",
        oauth_timestamp="${requestParams.oauth_timestamp}",
        oauth_nonce="${requestParams.oauth_nonce}",
        oauth_version="${requestParams.oauth_version}",
        oauth_signature="${encodedSignature}"
      `
    })
      .then(res => {
        this.setState({
          requestResponse: res
        })
      })
  }

Upvotes: 2

Views: 1620

Answers (1)

Mateusz Mysiak
Mateusz Mysiak

Reputation: 548

Finally, I've figured out what's the problem. It would be nice if Wordpress API had more examples. My authorization header was not properly set.

Below is the updated code that should be used in any Oauth 1.0 secured requests to Wordpress API (GET, POST, PUT, DELETE, just replace 'post' with any method in oauthSignature.generate() function and the axios request). Checked and working properly.

Just remember that this is just an example with all tokens and secrets in the component's state. You should store these in the backend and pass them to front-end only after providing some credentials.

I've uploaded the whole React component code, because I've learnt the hard way how many small, unusable snippets of code there are on the internet instead of a whole solution, which annoyed me greatly. This should be more explanatory to all those that want to have a working example.

// dependencies
import React, { Component } from 'react'
import axios from 'axios'
import oauthSignature from 'oauth-signature'
// components
import '../Styles/Css/Moderator.css'

class Moderator extends Component {
  constructor() {
    super()
    this.state = {
      requestResponse: null,
      parameters: {
        oauth_consumer_key : 'xxxxxxxxxxxxx', // your consumer_key
        oauth_token : 'xxxxxxxxxxxxxxxxx', // your token
        oauth_signature_method : 'HMAC-SHA1',
        oauth_timestamp : '',
        oauth_nonce : '',
        oauth_version : '1.0'
      },
      consumerSecret: 'xxxxxxxxxxxxxxxxxxxxx', // your consumer_secret
      tokenSecret: 'xxxxxxxxxxxxxxxxxxxxx', // your token_secret
    }
  }

  generateNonce = () => {
    let text = ''
    const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    for (let i = 0; i < 11; i++) {
      text += possible.charAt(Math.floor(Math.random() * possible.length))
    }
    return text
  }

  handleSubmit = (e) => {
    e.preventDefault()

    let postData = {
      title: this.refs.title.value,
      status: 'publish',
      content: this.refs.content.value,
    }

    const requestParams = { ...this.state.parameters }
    requestParams.oauth_nonce = this.generateNonce() // unique identifier
    requestParams.oauth_timestamp = new Date()
      .getTime()
      .toString()
      .slice(0,10) // we need just the first 10 digits from current time
    const encodedSignature = oauthSignature.generate(
      'POST',
      'http://localhost/wordpress-api/wp-json/wp/v2/posts',
      requestParams,
      this.state.consumerSecret,
      this.state.tokenSecret
    )

    const authorizationHeader = 
          'OAuth oauth_consumer_key="' + requestParams.oauth_consumer_key
          + '",oauth_token="' + requestParams.oauth_token
          + '",oauth_signature_method="' + requestParams.oauth_signature_method
          + '",oauth_timestamp="' + requestParams.oauth_timestamp
          + '",oauth_nonce="' + requestParams.oauth_nonce
          + '",oauth_version="' + requestParams.oauth_version
          + '",oauth_signature="' + encodedSignature +'"'

    axios({
      method: 'post',
      url: 'http://localhost/wordpress-api/wp-json/wp/v2/posts',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': authorizationHeader
      },
      data: postData
    })
      .then(res => {
        console.log(res)
      })
  }

  render() {
    return (
      <div className='moderator'>
        <form onSubmit={this.handleSubmit}>
          <label>
            Title
            <input type='text' ref='title' />
          </label><br />
          <label>
            Content
            <textarea ref='content' />
          </label>
          <input type='submit' value='Submit' />
        </form>
      </div>
    )
  }
}

export default Moderator

Upvotes: 5

Related Questions