oauth2_access_token_fetcher.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 4a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "google_apis/gaia/oauth2_access_token_fetcher.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm> 890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <string> 9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <vector> 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_reader.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/string_util.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stringprintf.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/time.h" 157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/values.h" 167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/escape.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/load_flags.h" 20a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "net/http/http_status_code.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_fetcher.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request_status.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::ResponseCookies; 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::URLFetcher; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::URLFetcherDelegate; 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::URLRequestContextGetter; 297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)using net::URLRequestStatus; 307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace { 32a3f7b4e666c476898878fa745f637129375cd889Ben Murdochstatic const char kGetAccessTokenBodyFormat[] = 33ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch "client_id=%s&" 347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) "client_secret=%s&" 357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) "grant_type=refresh_token&" 367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) "refresh_token=%s"; 377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static const char kGetAccessTokenBodyWithScopeFormat[] = 397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) "client_id=%s&" 407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) "client_secret=%s&" 417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) "grant_type=refresh_token&" 427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) "refresh_token=%s&" 437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) "scope=%s"; 447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static const char kAccessTokenKey[] = "access_token"; 467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static const char kExpiresInKey[] = "expires_in"; 477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static GoogleServiceAuthError CreateAuthError(URLRequestStatus status) { 497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) CHECK(!status.is_success()); 507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (status.status() == URLRequestStatus::CANCELED) { 517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); 527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } else { 537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DLOG(WARNING) << "Could not reach Google Accounts servers: errno " 547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) << status.error(); 557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return GoogleServiceAuthError::FromConnectionError(status.error()); 567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstatic URLFetcher* CreateFetcher(URLRequestContextGetter* getter, 607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const GURL& url, 617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::string& body, 627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) URLFetcherDelegate* delegate) { 637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) bool empty_body = body.empty(); 647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) URLFetcher* result = net::URLFetcher::Create( 657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 0, url, 667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) empty_body ? URLFetcher::GET : URLFetcher::POST, 677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) delegate); 687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) result->SetRequestContext(getter); 707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) result->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) net::LOAD_DO_NOT_SAVE_COOKIES); 727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Fetchers are sometimes cancelled because a network change was detected, 737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // especially at startup and after sign-in on ChromeOS. Retrying once should 74a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // be enough in those cases; let the fetcher retry up to 3 times just in case. 75a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // http://crbug.com/163710 767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) result->SetAutomaticallyRetryOnNetworkChanges(3); 777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!empty_body) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result->SetUploadData("application/x-www-form-urlencoded", body); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return result; 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OAuth2AccessTokenFetcher::OAuth2AccessTokenFetcher( 867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) OAuth2AccessTokenConsumer* consumer, 877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) URLRequestContextGetter* getter) 887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) : consumer_(consumer), 897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) getter_(getter), 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_(INITIAL) { } 917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 92ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochOAuth2AccessTokenFetcher::~OAuth2AccessTokenFetcher() { } 93ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 94ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid OAuth2AccessTokenFetcher::CancelRequest() { 95a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch fetcher_.reset(); 967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 97a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2AccessTokenFetcher::Start(const std::string& client_id, 997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::string& client_secret, 1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::string& refresh_token, 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<std::string>& scopes) { 10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) client_id_ = client_id; 1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) client_secret_ = client_secret; 1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) refresh_token_ = refresh_token; 1057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) scopes_ = scopes; 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StartGetAccessToken(); 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2AccessTokenFetcher::StartGetAccessToken() { 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK_EQ(INITIAL, state_); 1117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) state_ = GET_ACCESS_TOKEN_STARTED; 1127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) fetcher_.reset(CreateFetcher( 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getter_, 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MakeGetAccessTokenUrl(), 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MakeGetAccessTokenBody( 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client_id_, client_secret_, refresh_token_, scopes_), 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this)); 11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) fetcher_->Start(); // OnURLFetchComplete will be called. 11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 1207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OAuth2AccessTokenFetcher::EndGetAccessToken( 1227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const net::URLFetcher* source) { 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CHECK_EQ(GET_ACCESS_TOKEN_STARTED, state_); 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch state_ = GET_ACCESS_TOKEN_DONE; 1257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch URLRequestStatus status = source->GetStatus(); 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!status.is_success()) { 1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) OnGetTokenFailure(CreateAuthError(status)); 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // HTTP_FORBIDDEN (403) is treated as temporary error, because it may be 1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // '403 Rate Limit Exeeded.' 1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (source->GetResponseCode() == net::HTTP_FORBIDDEN) { 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnGetTokenFailure(GoogleServiceAuthError( 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GoogleServiceAuthError::SERVICE_UNAVAILABLE)); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // The other errors are treated as permanent error. 1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (source->GetResponseCode() != net::HTTP_OK) { 142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch OnGetTokenFailure(GoogleServiceAuthError( 143ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 144ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return; 145ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 147ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // The request was successfully fetched and it returned OK. 148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Parse out the access token and the expiration time. 149ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::string access_token; 150ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch int expires_in; 151a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (!ParseGetAccessTokenResponse(source, &access_token, &expires_in)) { 152a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch DLOG(WARNING) << "Response doesn't match expected format"; 153a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch OnGetTokenFailure( 154a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); 155a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return; 156a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 157a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // The token will expire in |expires_in| seconds. Take a 10% error margin to 158a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // prevent reusing a token too close to its expiration date. 159a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch OnGetTokenSuccess( 160a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch access_token, 161a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch base::Time::Now() + base::TimeDelta::FromSeconds(9 * expires_in / 10)); 162a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 163a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 164a3f7b4e666c476898878fa745f637129375cd889Ben Murdochvoid OAuth2AccessTokenFetcher::OnGetTokenSuccess( 165a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const std::string& access_token, 166a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const base::Time& expiration_time) { 167a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch consumer_->OnGetTokenSuccess(access_token, expiration_time); 168a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 169a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 170a3f7b4e666c476898878fa745f637129375cd889Ben Murdochvoid OAuth2AccessTokenFetcher::OnGetTokenFailure( 171a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const GoogleServiceAuthError& error) { 172a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch state_ = ERROR_STATE; 173a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch consumer_->OnGetTokenFailure(error); 174a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 175a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 176a3f7b4e666c476898878fa745f637129375cd889Ben Murdochvoid OAuth2AccessTokenFetcher::OnURLFetchComplete( 177a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const net::URLFetcher* source) { 178a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch CHECK(source); 179a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch CHECK(state_ == GET_ACCESS_TOKEN_STARTED); 180a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch EndGetAccessToken(source); 181a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 182a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 183a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// static 184a3f7b4e666c476898878fa745f637129375cd889Ben MurdochGURL OAuth2AccessTokenFetcher::MakeGetAccessTokenUrl() { 185a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return GURL(GaiaUrls::GetInstance()->oauth2_token_url()); 186a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 187a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 188a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// static 189a3f7b4e666c476898878fa745f637129375cd889Ben Murdochstd::string OAuth2AccessTokenFetcher::MakeGetAccessTokenBody( 190a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const std::string& client_id, 191a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const std::string& client_secret, 192a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const std::string& refresh_token, 193a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const std::vector<std::string>& scopes) { 194a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch std::string enc_client_id = net::EscapeUrlEncodedData(client_id, true); 195a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch std::string enc_client_secret = 196a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch net::EscapeUrlEncodedData(client_secret, true); 197a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch std::string enc_refresh_token = 198a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch net::EscapeUrlEncodedData(refresh_token, true); 199a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (scopes.empty()) { 200a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return base::StringPrintf( 201a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch kGetAccessTokenBodyFormat, 202a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch enc_client_id.c_str(), 203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch enc_client_secret.c_str(), 2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) enc_refresh_token.c_str()); 2057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } else { 2067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::string scopes_string = JoinString(scopes, ' '); 2077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return base::StringPrintf( 2087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) kGetAccessTokenBodyWithScopeFormat, 209bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch enc_client_id.c_str(), 210bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch enc_client_secret.c_str(), 211bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch enc_refresh_token.c_str(), 212bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch net::EscapeUrlEncodedData(scopes_string, true).c_str()); 213bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch } 2147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 215bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch 216bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// static 217bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochbool OAuth2AccessTokenFetcher::ParseGetAccessTokenResponse( 218bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch const net::URLFetcher* source, 2197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::string* access_token, 2207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int* expires_in) { 2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) CHECK(source); 2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) CHECK(access_token); 2237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::string data; 2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) source->GetResponseAsString(&data); 2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) scoped_ptr<base::Value> value(base::JSONReader::Read(data)); 2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) 2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return false; 2287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); 2307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return dict->GetString(kAccessTokenKey, access_token) && 2317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) dict->GetInteger(kExpiresInKey, expires_in); 2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)