Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
dev:oauth [2011/02/07 01:25]
sean
dev:oauth [2017/11/12 19:53] (current)
Line 1: Line 1:
-====== OAuth Key Exchange ======+<​html><​p id="​zotero-5-update-warning"​ style="​color:​ red; font-weight:​ bold">​We’re 
 +in the process of updating the documentation for 
 +<a href="​https://​www.zotero.org/​blog/​zotero-5-0">​Zotero 5.0</​a>​. Some documentation 
 +may be outdated in the meantime. Thanks for your understanding.</​p></​html>​
  
-In addition to users manually creating Zotero API keys from the zotero.org account settings, Zotero supports [[http://​oauth.net/​|OAuth]] for API key exchange. 
  
-===== Registering Your Application ===== +See [[dev/web_api/oauth]].
- +
-In order to start using OAuth to create API keys on behalf of users, you must [[/oauth/apps|register your application with Zotero]] to obtain a Client Key and Client Secret for use during all future OAuth handshakes between your application/​website and zotero.org. Note that after you obtain an API key for a particular user these client credentials are not required for further Zotero API requests. +
- +
-===== Using OAuth Handshake for Key Exchange ===== +
- +
-Below is an example php file implementing the application side of the OAuth handshake with zotero.org and using the key obtained to make a request to the Zotero API. +
- +
- +
-    <?php +
-    /** Note that this example uses the php OAuth extension http://​php.net/​manual/​en/​book.oauth.php +
-      * but there are various php libraries that provide similar functionality. +
-      * OAuth acts over multiple pages, so we save variables we need to remember in $state in a temp file +
-      *  +
-      * The OAuth handshake has 3 steps: +
-      * 1: Make a request to the provider to get a temporary token +
-      * 2: Redirect user to provider with a reference to the temporary token. The provider will ask them to authorize it +
-      * 3: When the user is sent back by the provider and the temporary token is authorized, exchange it for a permanent  +
-      *    token then save the permanent token for use in all future requests on behalf of this user. +
-      * +
-      * So an OAuth consumer needs to deal with 3 states which this example covers: +
-      * State 0: We need to start a fresh OAuth handshake for a user to authorize us to get their information. +
-      *         We get a request token from the provider and send the user off to authorize it +
-      * State 1: The provider just sent the user back after they authorized the request token +
-      *         We use the request token + secret we stored for this user and the verifier the provider just sent back to +
-      *         ​exchange the request token for an access token. +
-      * State 2: We have an access token stored for this user from a past handshake, so we use that to make data requests +
-      *         to the provider. +
-     **/ +
-    //​initialize some variables to start with. +
-    //​clientkey,​ clientSecret,​ and callbackurl should correspond to http://​www.zotero.org/​oauth/​apps +
-    $clientKey = '​9c6221a6ccae7639711a';​  +
-    $clientSecret = '​39091046dc9cf4dc3b61';​ +
-    $callbackUrl = '​http://​localhost/​oauthtestentry.php';​ +
-    //the endpoints are specific to the OAuth provider, in this case Zotero +
-    $request_token_endpoint = '​https://​www.zotero.org/​oauth/​request';​ +
-    $access_token_endpoint = '​https://​www.zotero.org/​oauth/​access';​ +
-    $zotero_authorize_endpoint = '​https://​www.zotero.org/​oauth/​authorize';​ +
-    //Functions to save state to temp file between requests, DB should replace this functionality +
-    function read_state(){ +
-        return unserialize(file_get_contents('/​tmp/​oauthteststate'​));​ +
-    } +
-    function write_state($state){ +
-        file_put_contents('/​tmp/​oauthteststate',​ serialize($state));​ +
-    } +
-    function save_request_token($request_token_info,​ $state){ +
-        // Make sure the request token has all the information we need +
-        if(isset($request_token_info['​oauth_token'​]) && isset($request_token_info['​oauth_token_secret'​])){ +
-            // save the request token for when the user comes back +
-            $state['​request_token_info'​] = $request_token_info;​ +
-            $state['​oauthState'​] = 1; +
-            write_state($state);​ +
-        } +
-        else{ +
-            die("​Request token did not return all the information we need."); +
-        } +
-    } +
-    function get_request_token($state){ +
-        if($_GET['​oauth_token'​] != $state['​request_token_info'​]['​oauth_token'​]){ +
-            die("​Could not find referenced OAuth request token"​);​ +
-        } +
-        else{ +
-            return $state['​request_token_info'​];​ +
-        } +
-    } +
-    function save_access_token($access_token_info,​ $state){ +
-        if(!isset($access_token_info['​oauth_token'​]) || !isset($access_token_info['​oauth_token_secret'​])){ +
-            //Something went wrong with the access token request and we didn't get the information we need +
-            throw new Exception("​OAuth access token did not contain expected information"​);​ +
-        } +
-        //we got the access token, so save it for future use +
-        $state['​oauthState'​] = 2; +
-        $state['​access_token_info'​] = $access_token_info;​ +
-        write_state($state);​ //save the access token for all subsequent resquests, in Zotero'​s case the token and secret are just the same Zotero API key +
-    } +
-    function get_access_token($state){ +
-        if(empty($state['​access_token_info'​])){ +
-            die("​Could not retrieve access token from storage."​);​ +
-        } +
-        return $state['​access_token_info'​];​ +
-    } +
-    //​Initialize our environment +
-    //check if there is a transaction in progress +
-    //for testing purpose, start with a fresh state to perform a new handshake +
-    if(empty($_GET['​reset'​]) && file_exists('/​tmp/​oauthteststate'​)){ +
-        $state = read_state();​ +
-    } +
-    else{ +
-        $state = array(); +
-        $state['​localUser'​] = '​localUserInformation';​ +
-        $state['​oauthState'​] = 0; //we do not have an oauth transaction in process yet +
-        write_state($state);​ +
-    } +
-    // If we are in state=1 there should be an oauth_token,​ if not go back to 0 +
-    if($state['​oauthState'​] == 1 && !isset($_GET['​oauth_token'​])){ +
-        $state['​oauthState'​] = 0; +
-    } +
-    //Make sure we have OAuth installed depending on what library you're using +
-    if(!class_exists('​OAuth'​)){ +
-        die("​Class OAuth does not exist. Make sure PHP OAuth extension is installed and enabled."​);​ +
-    } +
-    //set up a new OAuth object initialized with client credentials and methods accepted by the provider +
-    $oauth = new OAuth($clientKey,​ $clientSecret,​ OAUTH_SIG_METHOD_HMACSHA1,​ OAUTH_AUTH_TYPE_FORM);​ +
-    $oauth->​enableDebug();​ //get feedback if something goes wrong. Should not be used in production +
-    //Handle different parts of the OAuth handshake depending on what state we're in +
-    switch($state['​oauthState'​]){ +
-        case 0: +
-            // State 0 - Get request token from Zotero and redirect user to Zotero to authorize +
-            try{ +
-                $request_token_info = $oauth->​getRequestToken($request_token_endpoint,​ $callbackUrl);​ +
-            } +
-            catch(OAuthException $E){ +
-                echo "​Problem getting request token<br />";​ +
-                echo $E->​lastResponse;​ echo "<​br />";​ +
-                die; +
-            } +
-            save_request_token($request_token_info,​ $state); +
-             +
-            // Send the user off to the provider to authorize your request token +
-            // This could also be a link the user follows +
-            $redirectUrl = "​{$zotero_authorize_endpoint}?​oauth_token={$request_token_info['​oauth_token'​]}";​ +
-            header('​Location:​ ' . $redirectUrl);​ +
-            break; +
-        case 1: +
-            // State 1 - Handle callback from Zotero and get and store an access token +
-            // Make sure the token we got sent back matches the one we have +
-            // In practice we would look up the stored token and whatever local user information we have tied to it +
-            $request_token_info = get_request_token($state);​ +
-            //if we found the temp token, try to exchange it for a permanent one +
-            try{ +
-                //set the token we got back from the provider and the secret we saved previously for the exchange. +
-                $oauth->​setToken($_GET['​oauth_token'​],​ $request_token_info['​oauth_token_secret'​]);​ +
-                //make the exchange request to the provider'​s given endpoint +
-                $access_token_info = $oauth->​getAccessToken($access_token_endpoint);​ +
-                save_access_token($access_token_info,​ $state); +
-            } +
-            catch(Exception $e){ +
-                //Handle error getting access token +
-                die("​Caught exception on access token request"​);​ +
-            } +
-            // Continue on to authorized state outside switch +
-            break; +
-        case 2: +
-            //get previously stored access token if we didn't just get it from a handshack +
-            $access_token_info = get_access_token($state);​ +
-            break; +
-    } +
-    // State 2 - Authorized. We have an access token stored already which we can use for requests on behalf of this user +
-    echo "Have access token for user.";​ +
-    //zotero will send the userID associated with the key along too +
-    $zoteroUserID = $access_token_info['​userID'​];​ +
-    //Now we can use the token secret the same way we already used a Zotero API key +
-    $zoteroApiKey = $access_token_info['​oauth_token_secret'​];​ +
-    $feed = file_get_contents("​https://​api.zotero.org/​users/​{$zoteroUserID}/​items?​limit=1&​key={$zoteroApiKey}"​);​ +
-    var_dump($state);​ +
-    echo "<​pre>"​ . htmlentities($feed) . "</​pre>";​ +
-    /** OAuth support for all api requests may be added in the future +
-      * but for now secure https provides similar benefits anyway +
-     */ +
-    ?>+
dev/oauth.txt · Last modified: 2017/11/12 19:53 (external edit)