oauth2_access_token_fetcher.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/oauth2_access_token_fetcher.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stringprintf.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_status_code.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::ResponseCookies; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::URLFetcher; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::URLFetcherDelegate; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::URLRequestContextGetter; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::URLRequestStatus; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kGetAccessTokenBodyFormat[] = 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "client_id=%s&" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "client_secret=%s&" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "grant_type=refresh_token&" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "refresh_token=%s"; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kGetAccessTokenBodyWithScopeFormat[] = 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "client_id=%s&" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "client_secret=%s&" 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "grant_type=refresh_token&" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "refresh_token=%s&" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "scope=%s"; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kAccessTokenKey[] = "access_token"; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kExpiresInKey[] = "expires_in"; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static GoogleServiceAuthError CreateAuthError(URLRequestStatus status) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!status.is_success()); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status.status() == URLRequestStatus::CANCELED) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Could not reach Google Accounts servers: errno " 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << status.error(); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GoogleServiceAuthError::FromConnectionError(status.error()); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static URLFetcher* CreateFetcher(URLRequestContextGetter* getter, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& body, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) URLFetcherDelegate* delegate) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool empty_body = body.empty(); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) URLFetcher* result = net::URLFetcher::Create( 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, url, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) empty_body ? URLFetcher::GET : URLFetcher::POST, 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->SetRequestContext(getter); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::LOAD_DO_NOT_SAVE_COOKIES); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!empty_body) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->SetUploadData("application/x-www-form-urlencoded", body); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OAuth2AccessTokenFetcher::OAuth2AccessTokenFetcher( 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OAuth2AccessTokenConsumer* consumer, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) URLRequestContextGetter* getter) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : consumer_(consumer), 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) getter_(getter), 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_(INITIAL) { } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OAuth2AccessTokenFetcher::~OAuth2AccessTokenFetcher() { } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2AccessTokenFetcher::CancelRequest() { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_.reset(); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2AccessTokenFetcher::Start(const std::string& client_id, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& client_secret, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& refresh_token, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<std::string>& scopes) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_id_ = client_id; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_secret_ = client_secret; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) refresh_token_ = refresh_token; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scopes_ = scopes; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartGetAccessToken(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2AccessTokenFetcher::StartGetAccessToken() { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(INITIAL, state_); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = GET_ACCESS_TOKEN_STARTED; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_.reset(CreateFetcher( 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) getter_, 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MakeGetAccessTokenUrl(), 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MakeGetAccessTokenBody( 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_id_, client_secret_, refresh_token_, scopes_), 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this)); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->Start(); // OnURLFetchComplete will be called. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2AccessTokenFetcher::EndGetAccessToken( 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLFetcher* source) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(GET_ACCESS_TOKEN_STARTED, state_); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = GET_ACCESS_TOKEN_DONE; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) URLRequestStatus status = source->GetStatus(); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status.is_success()) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnGetTokenFailure(CreateAuthError(status)); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (source->GetResponseCode() != net::HTTP_OK) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnGetTokenFailure(GoogleServiceAuthError( 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The request was successfully fetched and it returned OK. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Parse out the access token and the expiration time. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string access_token; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expires_in; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ParseGetAccessTokenResponse(source, &access_token, &expires_in)) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Response doesn't match expected format"; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnGetTokenFailure( 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The token will expire in |expires_in| seconds. Take a 10% error margin to 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // prevent reusing a token too close to its expiration date. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnGetTokenSuccess( 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) access_token, 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time::Now() + base::TimeDelta::FromSeconds(9 * expires_in / 10)); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2AccessTokenFetcher::OnGetTokenSuccess( 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& access_token, 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::Time& expiration_time) { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) consumer_->OnGetTokenSuccess(access_token, expiration_time); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2AccessTokenFetcher::OnGetTokenFailure( 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GoogleServiceAuthError& error) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = ERROR_STATE; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) consumer_->OnGetTokenFailure(error); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2AccessTokenFetcher::OnURLFetchComplete( 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLFetcher* source) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(source); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(state_ == GET_ACCESS_TOKEN_STARTED); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndGetAccessToken(source); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL OAuth2AccessTokenFetcher::MakeGetAccessTokenUrl() { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GURL(GaiaUrls::GetInstance()->oauth2_token_url()); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string OAuth2AccessTokenFetcher::MakeGetAccessTokenBody( 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& client_id, 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& client_secret, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& refresh_token, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<std::string>& scopes) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string enc_client_id = net::EscapeUrlEncodedData(client_id, true); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string enc_client_secret = 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::EscapeUrlEncodedData(client_secret, true); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string enc_refresh_token = 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::EscapeUrlEncodedData(refresh_token, true); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scopes.empty()) { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return StringPrintf( 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kGetAccessTokenBodyFormat, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc_client_id.c_str(), 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc_client_secret.c_str(), 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc_refresh_token.c_str()); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string scopes_string = JoinString(scopes, ' '); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return StringPrintf( 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kGetAccessTokenBodyWithScopeFormat, 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc_client_id.c_str(), 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc_client_secret.c_str(), 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enc_refresh_token.c_str(), 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::EscapeUrlEncodedData(scopes_string, true).c_str()); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OAuth2AccessTokenFetcher::ParseGetAccessTokenResponse( 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLFetcher* source, 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* access_token, 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* expires_in) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(source); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(access_token); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string data; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source->GetResponseAsString(&data); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<base::Value> value(base::JSONReader::Read(data)); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dict->GetString(kAccessTokenKey, access_token) && 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dict->GetInteger(kExpiresInKey, expires_in); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 219