¿Cómo usar la autenticación OAuth con la API REST mediante comandos CURL?

27 dic 2015, 23:13:22
Vistas: 71.7K
Votos: 23

Estoy tratando de usar la API REST de WordPress con autenticación para obtener más datos de la API. He instalado el plugin OAuth, el plugin rest-api y he obtenido las credenciales API desde WP-CLI.

He descubierto cómo acceder a los datos sin autorización. Esto funciona:

// establecer nuestro punto final
$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>

Pero no puedo descifrar cómo autenticar con credenciales. Este es mi intento. No estoy seguro si "key" y "secret" son correctos.

// Credenciales OAuth de wp-cli
$ID = "4";
$Key = "l8XZD9lX89kb";
$Secret = "UUbcc8vjUkGjuDyvK1gRTts9sZp2N8k9tbIQaGjZ6SNOyR4d";

// establecer nuestro punto final
$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>

La salida es

Array
(
    [code] => rest_cannot_read
    [message] => Lo siento, no puedes ver las revisiones de esta entrada.
    [data] => Array
        (
            [status] => 401
        )
)

¿Cómo puedo hacer que esto funcione? Gracias.

1
Comentarios

Las cosas no son tan sencillas. He estado intentando escribir una respuesta pero es bastante larga. Podrías comenzar leyendo la documentación, especialmente El Flujo de Autorización. Este post también tiene un excelente tutorial.

cybmeta cybmeta
1 ene 2016 22:01:39
Todas las respuestas a la pregunta 4
6
16

Vayamos paso a paso aquí. Parece que estás intentando usar OAuth solo para autenticación, pero antes de poder hacerlo necesitas obtener el Token de Acceso que se utilizará para autenticarte cuando hagas tus llamadas API.

Debido a que esto usa OAuth versión 1, para obtener el Token de Acceso debes hacer lo siguiente:

  1. Primero, configura una aplicación, realiza una llamada al sitio para obtener el Token de Solicitud (credenciales temporales) usando el ID de Cliente y el Secreto de la aplicación.
  2. Segundo, realiza una llamada al sitio para Autorizar la aplicación con el Token de Solicitud del primer paso (interfaz de usuario, ver más abajo).
  3. Tercero, después de completar la autorización, realizas una llamada al sitio para obtener el Token de Acceso (ahora que la aplicación ha sido autorizada).

Recomiendo usar Postman para los primeros pasos, porque solo necesitan completarse una vez. Postman también manejará la generación del timestamp, nonce y oauth signature, así que si no estás usando una biblioteca OAuth, definitivamente deberías usar Postman. Una vez que tengas tu Token de Acceso puedes hacer las llamadas vía CURL sin ninguna biblioteca.

https://www.getpostman.com/

Primer Paso (configurar aplicación)

Instala el plugin WP OAuth 1, actívalo, luego ve al ítem del menú bajo Usuarios > Aplicaciones. Añade una nueva aplicación, completa el nombre y la descripción. Para el callback, usa la URL para redirigir al usuario (después de autorizar), o oop para el flujo Out-of-Band, que redirigirá a una página interna que muestra el token verificador (en lugar de redirigir).

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

Para proceder al segundo paso, se debe hacer una llamada a tu sitio, usando el ID de Cliente y el Secreto de Cliente de la aplicación creada, para obtener credenciales temporales (Token de Solicitud).

Abre Postman, crea una nueva llamada a http://website.com/oauth1/request, haz clic en la pestaña Autorización, selecciona OAuth 1.0 del menú desplegable, ingresa la Clave de Cliente, el Secreto de Cliente, establece el método de firma como HMAC-SHA1, habilita agregar parámetros al encabezado, codifica la firma oauth, luego haz clic en Actualizar Solicitud.

Solicitud OAuth1 en Postman

Postman generará automáticamente la firma, nonce y timestamp, y los agregará al encabezado (puedes verlos en la pestaña Encabezados).

Haz clic en Enviar y deberías obtener una respuesta que incluya oauth_token y oauth_token_secret: Respuesta de Solicitud OAuth1 en Postman

Estos valores se usarán en el siguiente paso para autorizar la aplicación bajo tu cuenta de usuario de WordPress.

Segundo Paso (autorizar aplicación)

El paso de autorización solo debe completarse una vez, este paso es visible para el usuario y es el que todos conocen. Este paso es necesario porque estás usando OAuth1, y la aplicación necesita asociarse con una cuenta de usuario de WordPress. Piensa en cuando un sitio te permite iniciar sesión con Facebook... te dirigen a Facebook donde inicias sesión y haces clic en "Autorizar"... esto debe hacerse, pero a través de tu sitio WordPress.

Recomiendo usar tu navegador web para este paso, ya que puedes fácilmente establecer las variables en la URL, y esto proporciona la página "Autorizar" para autorizar la aplicación.

Abre tu navegador web y escribe la URL de tu sitio, así: http://website.com/oauth1/authorize

Ahora agrega a esta URL, oauth_consumer_key (ID de Cliente), oauth_token y oauth_token_secret (del paso anterior). En mi ejemplo, esta es la URL completa:

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

Autorizar Aplicación OAuth1

Una vez que hagas clic en Autorizar, obtendrás otra pantalla con el token de verificación. En mi ejemplo, este es el token de verificación devuelto E0JnxjjYxc32fMr2AF0uWsZm.

Tercer Paso (obtener token de acceso)

Ahora que hemos autorizado la aplicación, necesitamos hacer una última llamada para obtener el Token de Autorización que se usará para todas tus llamadas API. Al igual que el primer paso, voy a usar Postman (porque la firma debe ser HMAC-SHA1), y esto hace que completar estos pasos sea 100 veces más fácil.

Abre Postman nuevamente y cambia la URL a http://website.com/oauth1/access.

Asegúrate de agregar el Token y el Secreto del Token (valores del primer paso), luego haz clic en Params para mostrar las cajas debajo de la URL. A la izquierda escribe oauth_verifier y a la derecha, ingresa el código del segundo paso, el Token de Verificación.

Paso de Acceso OAuth1 en Postman

Asegúrate de hacer clic en Actualizar Solicitud, luego haz clic en Enviar, y deberías obtener una respuesta con oauth_token y oauth_token_secret... ¡esto es lo que necesitas para hacer tus llamadas API! Descarta los originales del paso 1, guarda estos en tu código o en algún lugar seguro.

Respuesta de Acceso OAuth1 en Postman

Luego puedes hacer una llamada API a tu sitio, configurando los encabezados con el token y el secreto del token devueltos.

Puedes pasarlo de múltiples maneras, vía encabezado de Autorización, en parámetros GET, o POST (si está codificado como application/x-www-form-urlencoded). Ten en cuenta que DEBES pasar la firma, timestamp y nonce. No me di cuenta de cuánto tiempo me tomaría esta respuesta, así que actualizaré esto mañana con un ejemplo de cómo hacerlo con tu código.

Recomiendo encarecidamente instalar Rest API Log para que puedas ver el registro de llamadas API y ver qué se envió, qué se devolvió, etc. Esto ayudará enormemente con la depuración.

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

20 sept 2016 05:46:53
Comentarios

Lo sé, hay muchos tutoriales con Postman o herramientas similares, pero no puedo encontrar ningún tutorial que haga todo el proceso con funcionalidades CURL, es decir, código PHP puro. Eso es lo que quiero.

James Vu James Vu
20 sept 2016 11:30:50

@Dan9 Para ser honesto, eso no es realmente posible... al menos no con OAuth1, principalmente porque tienes que AUTORIZAR la aplicación bajo una cuenta de usuario. Todos los demás pasos son fáciles de hacer con CURL, el problema es usar CURL para iniciar sesión como un usuario de WordPress (lo que significa que necesitas almacenar credenciales en tu archivo PHP, lo cual NO es una buena idea), Y para autorizar la aplicación, lo cual podrías modificar el código base de OAuth1, pero sinceramente, si quieres usar CURL para hacer TODO... estás pensando en esto de manera equivocada y deberías buscar otra solución o método.

sMyles sMyles
20 sept 2016 18:01:12

@Dan9 con lo que estás intentando hacer, deberías usar un servidor OAuth2 en lugar de OAuth1, principalmente porque OAuth2 tiene nuevas características, incluyendo el tipo de concesión de Credenciales de Cliente, lo que evita tener que pasar por todos estos pasos http://bshaffer.github.io/oauth2-server-php-docs/grant-types/client-credentials/

sMyles sMyles
20 sept 2016 18:14:59

@Dan9 si estás 100% decidido a obtener ayuda para hacer esto a través de OAuth1, usando CURL, creo que es posible con algunos ajustes de código, pero como mencioné, esto significa que debes guardar el NOMBRE DE USUARIO y CONTRASEÑA de un usuario en el archivo PHP. Si estás de acuerdo con eso, házmelo saber y escribiré un tutorial para hacerlo usando CURL, no quiero perder tiempo escribiendo el tutorial si vas a usar OAuth2 o ya no lo necesitas

sMyles sMyles
20 sept 2016 18:16:21

@Dan9 bueno... ese es el punto... si vas a usar OAuth1, debes asociar una Cuenta de Usuario de WordPress. Básicamente piensa en el Token de Acceso como una clave API... la "Clave API" debe estar asociada a una cuenta de usuario... ahora si usas alguna cuenta estándar que configures depende de ti.. pero independientemente al usar OAuth1 DEBE estar asociada a una cuenta de usuario, de ahí el largo proceso para obtener el token de acceso.

sMyles sMyles
20 sept 2016 18:57:53

Por eso recomendé usar OAuth2 porque puedes usar el tipo de concesión de credenciales del cliente, con el cual solo haces una llamada CURL con esas credenciales, y te devuelve un token de acceso (sin necesidad de pasar por el largo proceso de autorización). Aquí están todos los tipos de concesión de OAuth2: http://bshaffer.github.io/oauth2-server-php-docs/overview/grant-types/

sMyles sMyles
20 sept 2016 19:00:01
Mostrar los 1 comentarios restantes
2

Agrego esto como otra respuesta para ayudarte a entender cómo hacer esto. Básicamente, como mencioné en mis comentarios, si vas a usar OAuth1 DEBES asociarlo a una cuenta de usuario, no hay forma de evitarlo.

Primero necesitas usar CURL para iniciar sesión en el sitio con un usuario y contraseña de WordPress, almacenar la cookie para poder usarla en tu llamada CURL a OAuth (asegúrate de actualizar tu llamada CURL para incluir la cookie):

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

Luego realiza la llamada a OAuth usando CURL con el Client ID y Client Secret, para obtener el token temporal de oauth y el secreto (Request Token)

Para realizar esta llamada (y la llamada para obtener el token de acceso), necesitas configurar correctamente tu llamada CURL. Consulta el final de esta respuesta para ver el código y referencias.

Después de obtener el token temporal de oauth y el secreto (Request Token), realiza una llamada CURL POST a esta URL de tu sitio:

http://website.com/oauth1/authorize

Luego deberás extraer todos los valores del HTML devuelto de la página de autorización, y enviar tu propio POST a la URL de acción del formulario.

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

Específicamente estos deben incluirse en tus datos POST para completar la "autorización" enviando a http://domain.com/wp-login.php?action=oauth1_authorize

  • _wpnonce -- Este es el valor nonce para el formulario a enviar, DEBE extraerse del input HTML y enviarse con tu POST

    consumer -- Este es un input oculto en el HTML (es una referencia a un Post ID así que debes extraerlo del input HTML

    oauth_token -- Este es un input oculto en el HTML (pero también deberías tenerlo ya)

    wp-submit -- Este debe tener el valor authorize

Aquí un ejemplo de HTML generado para la página de autenticación:

<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">Conectar Mi Autenticación</h2>

    <div class="login-info">
        <p>Hola <strong>admin</strong>,<br/> "Mi Demo OAuth" quisiera conectarse a Sitio Ejemplo.</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">Autorizar</button>
        <button type="submit" name="wp-submit" value="cancel" class="button button-large">Cancelar</button>
    </p>

</form>

Después de realizar el POST con todos esos valores/datos, este es el HTML que será devuelto con el código de autorización (así que necesitas extraer el valor dentro del bloque <code>:

<div id="login">
    <h1><a href="https://wordpress.org/" title="Powered by WordPress" tabindex="-1">Sitio Ejemplo</a></h1>
    <p>Tu token de verificación es <code>yGOYFpyawe8iZmmcizqVIw3f</code></p> <p id="backtoblog"><a href="http://website.com/">&larr; Volver a Sitio Ejemplo</a></p>
</div>

Una vez que tengas el token de verificación, puedes hacer una llamada a /oauth1/access usando el token de verificación, el token oauth y el secreto del token oauth. El token de verificación debe incluirse en los datos POST como oauth_verifier

Eso devolverá tu nuevo y permanente Token de Acceso, y ¡VOILÁ!

Código CURL de Ejemplo

A continuación un código de ejemplo para realizar la llamada CURL, la parte más importante es cómo se genera el oauth_signature:

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;
}

// Agrega request, authorize, etc al final de la URL basado en qué llamada estás haciendo
$url = "http://domain.com/oauth/";

$consumer_key = "CLIENT ID AQUÍ";
$consumer_secret = "CLIENT SECRET AQUÍ";

$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);

Este sitio explica exactamente cómo codificar la firma OAuth, y cómo enviarla usando CURL (recomiendo leer toda la página): https://hannah.wf/twitter-oauth-simple-curl-requests-for-your-own-data/

Más recursos sobre generación de firma OAuth1: https://stackoverflow.com/questions/24613277/oauth-signature-generation-using-hmac-sha1

Otros Recursos: http://collaboradev.com/2011/04/01/twitter-oauth-php-tutorial/

20 sept 2016 20:47:25
Comentarios

¿Cómo puedo obtener el Client ID y Client Secret y asociarlos con un usuario válido? Actualmente solo los administradores pueden crear una nueva aplicación y esto solo ocurre a través del panel de administración. Por cierto, he intentado generar oauth_signature como dijiste, pero por alguna razón, la respuesta siempre es json_oauth1_signature_mismatch.

James Vu James Vu
21 sept 2016 06:49:14

@Dan9 sí, eso es correcto, los administradores tienen que crear la aplicación, de lo contrario sería un gran problema de seguridad permitir que aplicaciones sean creadas por usuarios anónimos. Aquí hay algunos sitios relacionados con la firma http://wordpress.stackexchange.com/questions/185511/oauth-signature-does-not-match https://github.com/WP-API/OAuth1/issues/34 https://github.com/WP-API/OAuth1/issues/27

sMyles sMyles
21 sept 2016 20:55:22
0

Sé que llego un poco tarde a esto, pero ¿puedes usar wp_remote_get y _post?

Estoy obteniendo y publicando contenido con mi instalación de WordPress usándolos:

Esta es la idea general del codex de WordPress:

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

Aquí hay un ejemplo más específico:

$url='http://WWW.EJEMPLOAQUI.';
$response = wp_remote_post( $url, array(
    'method' => 'POST',
    'timeout' => 45,
    'redirection' => 5,
    'httpversion' => '1.0', //necesario para obtener una respuesta
    'blocking' => true,
    'headers' => array('Authorization' => 'Basic ' . base64_encode( 'MI TOKENID' . ':' . '' )),
    'body' => $body // en array
    'cookies' => array()
    )
);

if ( is_wp_error( $response ) ) {
   $error_message = $response->get_error_message();
   echo "Algo salió mal: $error_message";
} else {
 //  echo 'Respuesta:<pre>';
 //  print_r( $response );
 //    echo '</pre>'; 
$responseBody = json_decode($response['body'],true);
echo $responseBody['message'];

    }
    }
}

El truco está en codificar el nombre de usuario y la contraseña. A menudo, dependiendo de la API, el nombre de usuario y la contraseña estarán en blanco o serán tus tokens.

Por ejemplo, en mi ejemplo específico de arriba, los encabezados eran

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

y dejé la contraseña en blanco. Pero eso depende del sistema de API que estés usando.

20 sept 2016 23:44:26
0

Actualización: Según lo que he leído, necesitas hacer múltiples solicitudes cURL para obtener el access_token, que luego usas para realizar la consulta

  • Adquisición de Credenciales Temporales: El cliente obtiene un conjunto de credenciales temporales del servidor.
  • Autorización: El usuario "autoriza" el token de solicitud para acceder a su cuenta.
  • Intercambio de Token: El cliente intercambia las credenciales temporales de corta duración por un token de larga duración.

flujo del servidor oauth1

15 abr 2016 15:37:22