1: <?php
2: namespace Dropbox;
3:
4: /**
5: * Use {@link WebAuth::start()} and {@link WebAuth::finish()} to guide your
6: * user through the process of giving your app access to their Dropbox account. At the end, you
7: * will have a {@link AccessToken}, which you can pass to {@link Client} and start making
8: * API calls.
9: *
10: * This class is stateless so it can be shared/reused.
11: */
12: final class WebAuth
13: {
14: /**
15: * The config used when making requests to the Dropbox server.
16: *
17: * @return Config
18: */
19: function getConfig() { return $this->config; }
20:
21: /** @var Config */
22: private $config;
23:
24: /**
25: * Constructor.
26: *
27: * @param Config $config
28: * See {@link getConfig()}
29: */
30: function __construct($config)
31: {
32: Config::checkArg("config", $config);
33: $this->config = $config;
34: }
35:
36: /**
37: * Tells Dropbox that you want to start authorization and returns the information necessary
38: * to continue authorization. This corresponds to step 1 of the three-step OAuth web flow.
39: *
40: * After this function returns, direct your user to the returned <code>$authorizeUrl</code>,
41: * which gives them a chance to grant your application access to their Dropbox account. This
42: * corresponds to step 2 of the three-step OAuth web flow.
43: *
44: * If they choose to grant access, they will be redirected to the URL you provide for
45: * <code>$callbackUrl</code>, after which you should call {@link finish()} to get an
46: * access token.
47: *
48: * <code>
49: * use \Dropbox as dbx;
50: * $config = new dbx\Config(...);
51: * $webAuth = new dbx\WebAuth($config);
52: * $callbackUrl = "https://example.org/dropbox-auth-finish";
53: * list($requestToken, $authorizeUrl) = $webAuth->start($callbackUrl);
54: * $_SESSION['dropbox-request-token'] = $requestToken->serialize();
55: * header("Location: $authorizeUrl");
56: * </code>
57: *
58: * @param string $callbackUrl
59: * The URL that the Dropbox servers will redirect the user to after the user finishes
60: * authorizing your app. If this is <code>null</code>, the user will not be redirected.
61: *
62: * @return array
63: * A <code>list(RequestToken $requestToken, string $authorizeUrl)</code>. Redirect the
64: * user's browser to <code>$authorizeUrl</code>. When they're done authorizing, call
65: * {@link finish()} with <code>$requestToken</code>.
66: *
67: * @throws Exception
68: */
69: function start($callbackUrl)
70: {
71: Checker::argStringOrNull("callbackUrl", $callbackUrl);
72:
73: $url = RequestUtil::buildUri(
74: $this->config->getAppInfo()->getHost()->getApi(),
75: "1/oauth/request_token");
76:
77: $params = array(
78: "oauth_signature_method" => "PLAINTEXT",
79: "oauth_consumer_key" => $this->config->getAppInfo()->getKey(),
80: "oauth_signature" => rawurlencode($this->config->getAppInfo()->getSecret()) . "&",
81: "locale" => $this->config->getUserLocale(),
82: );
83:
84: $curl = RequestUtil::mkCurlWithoutAuth($this->config, $url);
85: $curl->set(CURLOPT_POST, true);
86: $curl->set(CURLOPT_POSTFIELDS, RequestUtil::buildPostBody($params));
87:
88: $curl->set(CURLOPT_RETURNTRANSFER, true);
89: $response = $curl->exec();
90:
91: if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
92:
93: $parts = array();
94: parse_str($response->body, $parts);
95: if (!array_key_exists('oauth_token', $parts)) {
96: throw new Exception_BadResponse("Missing \"oauth_token\" parameter.");
97: }
98: if (!array_key_exists('oauth_token_secret', $parts)) {
99: throw new Exception_BadResponse("Missing \"oauth_token_secret\" parameter.");
100: }
101: $requestToken = new RequestToken($parts['oauth_token'], $parts['oauth_token_secret']);
102:
103: $authorizeUrl = RequestUtil::buildUrl(
104: $this->config,
105: $this->config->getAppInfo()->getHost()->getWeb(),
106: "1/oauth/authorize",
107: array(
108: "oauth_token" => $requestToken->getKey(),
109: "oauth_callback" => $callbackUrl,
110: ));
111:
112: return array($requestToken, $authorizeUrl);
113: }
114:
115: /**
116: * Call this after the user has visited the authorize URL
117: * (returned by {@link start()}) and approved your app. This corresponds to
118: * step 3 of the three-step OAuth web flow.
119: *
120: * Example (see {@link start() for first part):
121: * <code>
122: * // In the request handler for "/dropbox-auth-finish"
123: * $givenKey = $_GET['oauth_token'];
124: * $requestToken = RequestToken::deserialize($_SESSION['dropbox-request-token'])
125: * if (!$requestToken->matchesKey($givenKey)) {
126: * // Do not continue. You could show an error or redirect back to
127: * // the beginning of the authorization process.
128: * }
129: * $webAuth = new dbx\WebAuth($config);
130: * list($accessToken, $dropboxUserId) = $webAuth->finish($requestToken);
131: * saveDropboxAccessTokenInYourDatabase($accessToken->serialize());
132: * </code>
133: *
134: * @param RequestToken $requestToken
135: * The <code>RequestToken</code> returned by {@link start()}.
136: *
137: * @return array
138: * A <code>list(RequestToken $requestToken, string $dropboxUserId)</code>. Use
139: * <code>$requestToken</code> to construct a {@link Client} object and start making
140: * API calls. <code>$dropboxUserId</code> is the user ID of the user's Dropbox
141: * account and is for your own reference.
142: *
143: * @throws Exception
144: */
145: function finish($requestToken)
146: {
147: RequestToken::checkArg("requestToken", $requestToken);
148:
149: $response = RequestUtil::doPost(
150: $this->config,
151: $requestToken,
152: $this->config->getAppInfo()->getHost()->getApi(),
153: "1/oauth/access_token");
154:
155: if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
156:
157: $parts = array();
158: parse_str($response->body, $parts);
159: if (!array_key_exists('oauth_token', $parts)) {
160: throw new Exception_BadResponse("Missing \"oauth_token\" parameter.");
161: }
162: if (!array_key_exists('oauth_token_secret', $parts)) {
163: throw new Exception_BadResponse("Missing \"oauth_token_secret\" parameter.");
164: }
165: if (!array_key_exists('uid', $parts)) {
166: throw new Exception_BadResponse("Missing \"uid\" parameter.");
167: }
168:
169: $accessToken = new AccessToken($parts['oauth_token'], $parts['oauth_token_secret']);
170: return array($accessToken, $parts['uid']);
171: }
172: }
173: