Jump to content

New API login/authorization example

Recommended Posts

It took me way too long to figure out some things with the new API, so I'm posting a working bit of my API-testing PHP code, in the hopes that it saves others some trouble.

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $tokenExchangeURL);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded')); // important for this API!!!
  // note that grant_type=authorization_code is specific to the ORIGINAL auth process; after the token expires in one hour, 
  // the re-issue request will use grant_type=refresh_token instead 
  curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  $output = curl_exec($ch);

  $data_array = json_decode($output);
  $access_token = $data_array->access_token; // a very long JSON web token field
  $bearer = $data_array->bearer;
  $expires_in = $data_array->expires_in; // how many seconds before this token expires
  $refresh_token = $data_array->refresh_token;
  $APIReturnedToken = $access_token;
  // you may not care about the data embedded inside the access_token value, but it's a standard JSON web token (JWT) 
  // with some interesting stuff there - most useful being the user_name field which is the geocaching.com username for
  // the person doing the authorization
  try {
    $ValidationObject = JWT::decode($access_token, '', false); // you need to find some library to decode JSON web tokens
    // the next three values have very long key names; not happy about that but so be it...
    $user_name = mysql_real_escape_string($ValidationObject->{'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'});
    $user_id = mysql_real_escape_string($ValidationObject->{'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'});
    // note that this user_id is NOT the same as the user's referenceCode which is essential to requesting user data via the API.
    // not sure why it was changed, or why they don't just return the referenceCode instead.
    $user_data = mysql_real_escape_string($ValidationObject->{'http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata'});
    // there is other stuff in the JWT; the above just happens to be all that was important for this particular test
    $access_token = mysql_real_escape_string($access_token); // escaped so they can be safely stored in a database later
    $refresh_token = mysql_real_escape_string($refresh_token);
    $expires_in = 1*$expires_in; // this is an integer value and seems to be one hour long each time, at least on the staging server
  } catch (Exception $e) {
     if ($grant_type == 'authorization_code') {
      header('Location: https://www.geochecker.com/plus_test.php?message=The token from geocaching.com was malformed. Please try again. The error was: ' . $e->getMessage());
      return 'Failure';
    } else {
      return $e->getMessage();
  // get user's referenceCode for later use
  // this is a good quick demo of actually using the API now that the above authorization is done
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: bearer ' . $access_token)); 
    // this header is critical!!! This is universal for all other API calls once authorization is done.
  curl_setopt($ch, CURLOPT_URL, $APILink);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  $output = curl_exec($ch);
  $responsecode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  $response = json_decode($output);
  if ($responsecode!=200) {
    $response = json_decode($output);
    $statusMessage = $response->statusMessage;
    $errorMessage = $response->errorMessage;
    return "Error: Geocaching said \"$statusMessage\"";
  $referenceCode = $response[0]->referenceCode;

This is very rough code but it does work for an initial authorization.


Note the CURLOPT_HTTPHEADER optional header which is where the actual access token is used as part of any following query to the API. It's no longer used as part of the POST or GET fields.


Note that quite a few user data queries require the referenceCode value to identify the exact user. As far as I can tell, there is a completely new Base31-based encoding of the previous long-integer-based user ID value, and it's not a standard Base31 encoding but something that skips over some letters like i, l, s, and o (like if hexadecimal was changed to 0123456789ABDFGH by skipping C and E...). So I added the bottom third of the code to retrieve the user's new-format referenceCode value and immediately stuff it in a database for future reference. It's a critical input to find the user data.


Besides, that bottom bit of code does serve to show a good practical example of doing a basic query using the API.


Also, note that the new API liberally uses non-typical http methods "PUT" and "DELETE", in addition to the usual "GET" and "POST". This is very different than the older setup. So in PHP you will need to use the CURL option:

    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");

I'm not sure why this is needed, because now a lot of the queries use a confusing mix of GET and other methods. There's a lot going on and it's not well-documented yet.

Link to comment

All this is pretty standard OAuth2. Read up on it and the flow will make more sense.


Also, you mention the use of "non-typical http methods" but that really isn't the case with REST web services. Read up on REST web service implementations and you will find that this is all pretty standard stuff.

  • Upvote 1
Link to comment

First of all, thanks for the snippet. ?

But FYI I think your site is vulnerable to XSS because it's just echoing the user-controlled input back to the screen.



Link to comment
On 11/29/2019 at 4:56 PM, Zor said:

Ok, so I am just now getting back to this. What is the redirect URI? Was this something GSP was supposed to ask for or can we put anything we want to bounce back to here?

Geocaching HQ has asked their API partners, multiple times, for both their staging and production redirect URIs. The production redirect URI has to be secure, i.e., use https.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...