17

I am trying to use the WordPress Rest Api with authentication to get more data from the API. I have installed the Oauth plugin, rest-api plugin, and gotten API credentials from WP-CLI.

I have figured out how to access data without authorization. This works:

// set our end point
$domain = "http://localhost/wp-api";
$endpoint = $domain."/wp-json/wp/v2/posts/";


$curl = curl_init($endpoint);

curl_setopt_array($curl, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_URL            => $endpoint,
]);
$response = curl_exec($curl);
$decoderesponse = json_decode($response, true);

?>

<pre>
  <?php print_r($decoderesponse); ?>
</pre>

But I can't figure out how to authenticate with credentials. Here is my attempt. I am not sure if "key" and "secret" are correct.

// Oauth credentials from wp-cli
$ID = "4";
$Key = "l8XZD9lX89kb";
$Secret = "UUbcc8vjUkGjuDyvK1gRTts9sZp2N8k9tbIQaGjZ6SNOyR4d";

// set our end point
$domain = "http://localhost/wp-api";
$endpoint = $domain."/wp-json/wp/v2/posts/1/revisions";

$headers[] = "key=$Key";
$headers[] = "secret=$Secret";

$curl = curl_init($endpoint);

curl_setopt_array($curl, [
  CURLOPT_HTTPHEADER     => $headers,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_URL            => $endpoint,
]);
$response = curl_exec($curl);
$decoderesponse = json_decode($response, true);

?>

<pre>
  <?php print_r($decoderesponse); ?>
</pre>

The output is

Array
(
    [code] => rest_cannot_read
    [message] => Sorry, you cannot view revisions of this post.
    [data] => Array
        (
            [status] => 401
        )
)

How can I get this to work? Thank you.

  • 2
    Things are not so easy. I've been trying to write an answer but it is quite long. You could start by reading the docs, specially The Authorization Flow. This posts has also a great tutorial. – cybmeta Jan 1 '16 at 20:01
9
+150

Let's go step by step here. Looks like you're trying to use OAuth just for authentication, but before you can do so you need to get the Access Token which will be used to authenticate when you make your API calls.

Because this is using OAuth version 1, in order to obtain the Access Token you must do the following:

  1. First, setup an application, make a call to the site to obtain the Request Token (temp credentials) using the Client ID and Secret for the application
  2. Second, make a call to the site to Authorize the application with the Request Token from first step (user-facing, see below).
  3. Third, after authorization has been completed, you then make a call to the site to obtain the Access Token (now that application has been authorized)

I recommend using Postman for the first few steps, because they only need to be completed once. Postman will also handle generating the timestamp, nonce and oauth signature, so if you're not using an OAuth library, then you should absolutely use Postman. Once you have your Access Token you can make the calls via CURL without any libraries.

https://www.getpostman.com/

First Step (setup application)

Install WP OAuth 1 plugin, activate, then goto menu item under Users > Applications. Add new application, fill out name and description. For callback either the URL to redirect the user to (after authorizing), or oop for Out-of-Band flow which will redirect to an internal page which displays the verifier token (instead of redirecting).

https://github.com/WP-API/OAuth1/blob/master/docs/basics/Registering.md

To proceed to the second step a call needs to be made to your site, using the Client ID and Client Secret from the created application, to get temporary credentials (Request Token).

Open up Postman, create a new call to http://website.com/oauth1/request, click on the Authorization tab, select OAuth 1.0 from dropdown, enter in the Client Key, Client Secret, set signature method to HMAC-SHA1, enable add params to header, encode oauth signature, then click Update Request

Postman OAuth1 Request

Postman will auto generate the signature, nonce, and timestamp for you, and add them to the header (you can view under Headers tab).

Click Send and you should get a response that includes oauth_token and oauth_token_secret: Postman OAuth1 Request Response

These values will be used in the next step to authorize the application under your WordPress user account.

Second Step (authorize application)

Authorization step only needs to be completed once, this step is user-facing, and the one that everyone is familiar with. This step is required because you're using OAuth1, and the application needs to be associated with a WordPress user account. Think of when a site allows you to login with Facebook ... they direct you to Facebook where you login and click "Authorize" ... this needs to be done, just through your WordPress site.

I recommend using your Web Browser for this step, as you can easily just set the variables in URL, and this provides the "Authorize" page to authorize the application.

Open your web browser and type in the URL to your site, like this: http://website.com/oauth1/authorize

Now add on to this URL, oauth_consumer_key (Client ID), oauth_token and oauth_token_secret (from previous step). In my example this is the full URL:

http://website.com/oauth1/authorize?oauth_consumer_key=TUPFNj1ZTd8u&oauth_token=J98cN81p01aqSdFd9rjkHZWI&oauth_token_secret=RkrMhw8YzXQljyh99BrNHmP7phryUvZgVObpmJtos3QExG1O

OAuth1 Authorize Application

Once you click on Authorize, you will get another screen with the verification token. In my example this is the verification token returned E0JnxjjYxc32fMr2AF0uWsZm

Third Step (get access token)

Now that we have authorized the application, we need to make one last call to get the Authorization Token which will be used to make all your API calls. Just like the first step i'm going to use Postman (because signature is required to be HMAC-SHA1), and it makes it 100x easier to complete these steps.

Open up Postman again, and change the URL to http://website.com/oauth1/access

Make sure to add the Token, and Token Secret (values from the first step), then click on Params to show the boxes below the URL. On the left type in oauth_verifier and on the right, enter the code from the second step, the Verification Token

Postman OAuth1 Access Step

Make sure to click Update Request, then click Send, and you should get a response back with oauth_token and oauth_token_secret ... this is what you need to make your API calls with! Discard the original ones from step 1, save these ones in your code or somewhere else safe.

Postman OAuth1 Access Response

You can then make an API call to your site, setting the headers with the returned token, and token secret.

You can pass this multiple ways, via Authorization header, in GET parameters, or POST (if encoded as application/x-www-form-urlencoded). Keep in mind you MUST pass the signature, timestamp, and nonce. I didn't realize how long this reply would take me, so i'll update this tomorrow with example on doing that with your code.

I strongly recommend installing Rest API log so you can view log of API calls, and see what was sent, returned, etc. This will help with debugging tremendously.

https://github.com/petenelson/wp-rest-api-log

  • I know, there're many tutorials with Postman or similar tools but I cannot find any tutorials which to do the entire process with CURL functionalities, i mean pure PHP code. That's what i want. – MinhTri Sep 20 '16 at 8:30
  • @Dan9 TBH that's not really possible ... at least not with OAuth1, mainly because you have to AUTHORIZE the application under a user account. All the other steps are easy to do with CURL, the problem is using CURL to login as a WordPress user (which means you need to store credentials in your PHP file which is NOT a good idea), AND to authorize the application, which you could modify the OAuth1 codebase, but honestly if you want to use CURL to do EVERYTHING ... you're thinking about this the wrong way, and should come up with another solution or method. – sMyles Sep 20 '16 at 15:01
  • @Dan9 with what you're trying to do, you should use OAuth2 server instead of OAuth1, mainly because the fact that OAuth2 has new features including the Client Credential grant type, which avoids having to go through all these steps bshaffer.github.io/oauth2-server-php-docs/grant-types/… – sMyles Sep 20 '16 at 15:14
  • @Dan9 if you're 100% set on getting help with doing this through OAuth1, using CURL, I do think it's possible with a few code hacks, but as I mentioned, this means you have to save the USERNAME and PASSWORD of a user to the PHP file. If you're fine with that, let me know and ill write up a tutorial to do it using CURL, don't want to spend the time writing tutorial if you're going to go with OAuth2 or don't need this anymore – sMyles Sep 20 '16 at 15:16
  • @Dan9 well ... that's just it ... if you're going to use OAuth1, you have to associate a WordPress User Account. Basically think of the Access Token like an API key ... the "API Key" has to be associated with a user account ... now whether you use some standard account you setup is up to you .. but regardless when using OAuth1 it MUST be associated with a user account, hence the lengthy process to obtain the access token. – sMyles Sep 20 '16 at 15:57
2

Adding this as another answer to give you help to figure out how to do this. Basically as mentioned in my comments if you're going to use OAuth1 you MUST associate it with a user account, no way around that.

First you need to use CURL to login to the site with a username password for WordPress, store the cookie so you can use it in your CURL call to OAuth (make sure to update your CURL call to include the cookie):

https://stackoverflow.com/questions/724107/wordpress-autologin-using-curl-or-fsockopen-in-php

Then make the call to OAuth using CURL with the Client ID and Client Secret, to obtain the temporary oauth token and secret (Request Token)

To make this call (and the call to obtain access token), you need to setup your CURL call correctly. See end of this answer for code and references.

After you obtain the temporary oauth token and secret (Request Token), make a CURL POST call to this URL of your site:

http://website.com/oauth1/authorize

You will then need to pull all the values from the returned HTML for the authorization page, and then submit your own POST to the form action URL.

https://stackoverflow.com/questions/35363815/how-to-get-a-value-input-from-html-returned-of-curl

Specifically these need to be included in your POST data to complete the "authorization" POSTing to http://domain.com/wp-login.php?action=oauth1_authorize

  • _wpnonce -- This is the nonce value for the form to be submitted, this MUST be pulled from the HTML input and submitted with your POST

    consumer -- This is a hidden input in the HTML (this is reference to a Post ID so you must pull it from the HTML input

    oauth_token -- This is a hidden input in the HTML (but you should also already have this)

    wp-submit -- This needs to be set to the value authorize

Here's example HTML generated for the authentication page:

<form name="oauth1_authorize_form" id="oauth1_authorize_form" action="http://website.com/wp-login.php?action=oauth1_authorize" method="post">

    <h2 class="login-title">Connect My Auth</h2>

    <div class="login-info">
        <p>Howdy <strong>admin</strong>,<br/> "My OAuth Demo" would like to connect to Example Site.</p>

    </div>

    <input type="hidden" name="consumer" value="5428" /><input type="hidden" name="oauth_token" value="i1scugFXyPENniCP4kABKtGb" /><input type="hidden" id="_wpnonce" name="_wpnonce" value="ca9b267b4f" /><input type="hidden" name="_wp_http_referer" value="/wp-login.php?action=oauth1_authorize&amp;oauth_consumer_key=TUPFNj1ZTd8u&amp;oauth_token=i1scugFXyPENniCP4kABKtGb&amp;oauth_token_secret=gzqW47pHG0tilFm9WT7lUgLoqN2YqS6tFFjUEiQoMgcmG2ic" />   <p class="submit">
        <button type="submit" name="wp-submit" value="authorize" class="button button-primary button-large">Authorize</button>
        <button type="submit" name="wp-submit" value="cancel" class="button button-large">Cancel</button>
    </p>

</form>

After you make the POST with all those values/data, this is the HTML that will be returned with the authorization code (so you need to pull the value from inside the <code> block:

<div id="login">
    <h1><a href="https://wordpress.org/" title="Powered by WordPress" tabindex="-1">Example Site</a></h1>
    <p>Your verification token is <code>yGOYFpyawe8iZmmcizqVIw3f</code></p> <p id="backtoblog"><a href="http://website.com/">&larr; Back to Example Site</a></p>
</div>

Once you have the verification token, you can then make a call to /oauth1/access using the verification token, oauth token, and oauth token secret. The verification token needs to be put in the POST data as oauth_verifier

That will return your new and permanent Access Token, and VOILA!

Example CURL Code

Below is example code to make the CURL call, the most important part being how the oauth_signature is generated:

https://oauth1.wp-api.org/docs/basics/Signing.html

function buildBaseString($baseURI, $method, $params){
    $r = array();
    ksort($params);
    foreach($params as $key=>$value){
        $r[] = "$key=" . rawurlencode($value);
    }

    return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
}

function buildAuthorizationHeader($oauth){
    $r = 'Authorization: OAuth ';
    $values = array();
    foreach($oauth as $key=>$value)
        $values[] = "$key=\"" . rawurlencode($value) . "\"";

    $r .= implode(', ', $values);
    return $r;
}

// Add request, authorize, etc to end of URL based on what call you're making
$url = "http://domain.com/oauth/";

$consumer_key = "CLIENT ID HERE";
$consumer_secret = "CLIENT SECRET HERE";

$oauth = array( 'oauth_consumer_key' => $consumer_key,
                'oauth_nonce' => time(),
                'oauth_signature_method' => 'HMAC-SHA1',
                'oauth_callback' => 'oob',
                'oauth_timestamp' => time(),
                'oauth_version' => '1.0');

$base_info = buildBaseString($url, 'GET', $oauth);
$composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;


$header = array(buildAuthorizationHeader($oauth), 'Expect:');
$options = array( CURLOPT_HTTPHEADER => $header,
                  CURLOPT_HEADER => false,
                  CURLOPT_URL => $url,
                  CURLOPT_RETURNTRANSFER => true,
                  CURLOPT_SSL_VERIFYPEER => false);

$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);

$return_data = json_decode($json);

print_r($return_data);

This site tells exactly how to encode the OAuth signature, and how to send using CURL (i recommend reading the entire page): https://hannah.wf/twitter-oauth-simple-curl-requests-for-your-own-data/

More resource on generating OAuth1 signature: https://stackoverflow.com/questions/24613277/oauth-signature-generation-using-hmac-sha1

Other Resources: http://collaboradev.com/2011/04/01/twitter-oauth-php-tutorial/

  • How can I get Client ID and Client secret and associate it with a valid user? Currently, only admins can create a new app and it happens through admin dashboard only. Btw, I have try to generate oauth_signature as you told but, somehow, the response is always json_oauth1_signature_mismatch. – MinhTri Sep 21 '16 at 3:49
  • @Dan9 yes that is correct, admins have to create the app, otherwise that would be a huge security issue allowing apps to be created by anonymous users. Here's some sites regarding signature wordpress.stackexchange.com/questions/185511/… github.com/WP-API/OAuth1/issues/34 github.com/WP-API/OAuth1/issues/27 – sMyles Sep 21 '16 at 17:55
0

Update: From what I've read, you need to do multiple curls to get the access_token, which you then use to do the query

  • Temporary Credentials Acquisition: The client gets a set of temporary credentials from the server.
  • Authorization: The user "authorizes" the request token to access their account.
  • Token Exchange: The client exchanges the short-lived temporary credentials for a long-lived token.

oauth1 server flow

0

I know I'm coming into this a bit late, but can you use wp_remote_get and _post?

I'm pulling and posting content with my wordpress install using them:

THis is the general idea from the wordpress codex:

$response = wp_remote_post( $url, array(
    'body'    => $data,
    'httpversion' => '1.0',
    'sslverify' => false,
    'headers' => array(
        'Authorization' => 'Basic ' . base64_encode( $username . ':' . $password ),
    ),
) );

Here is a more specific example:

$url='http://WWW.EXAMPLE HERE.';
$response = wp_remote_post( $url, array(
    'method' => 'POST',
    'timeout' => 45,
    'redirection' => 5,
    'httpversion' => '1.0', //needed to get a response
    'blocking' => true,
    'headers' => array('Authorization' => 'Basic ' . base64_encode( 'MY TOKENID' . ':' . '' )),
    'body' => $body // in array
    'cookies' => array()
    )
);

if ( is_wp_error( $response ) ) {
   $error_message = $response->get_error_message();
   echo "Something went wrong: $error_message";
} else {
 //  echo 'Response:<pre>';
 //  print_r( $response );
 //    echo '</pre>'; 
$responseBody = json_decode($response['body'],true);
echo $responseBody['message'];

    }
    }
}

The trick is encoding the username and pw. Now often time depending on the API username and pw will either be blank or will be your tokens.

so for instance in my specific example above, the headers were

'headers' => array('Authorization' => 'Basic ' . base64_encode( 'MYTOKENID' . ':' . '' ))

and i left pw blank. That's up to the API system you're using though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.