While developing an Android application for creating photo slideshows, I was faced with the task of publishing ready-made videos on YouTube’s personal channel.
I had to tinker, because First, we use cloud computing and data processing can take longer than the token. And secondly, to implement the function, I had to face some inaccuracies and questions in the Google manual. Details under the cut.
The essence of the task:
When the user has selected all the photos on his Android and decided on the music, the data for processing is sent to the server, and the user is prompted to specify where to put the finished video: in the on-line collection on our server, on the YouTube application’s shared channel YouTube channel. (Also to the email address comes a link for downloading the video).
If you choose to publish on a personal channel, we ask permission and upon confirmation, we get the token required to access the channel, which is saved on the server with the user data and remains valid for 60 minutes.
But if the user has a slow Internet (long upload of photos) or a queue has accumulated on the server, the token becomes invalid, a second request is required. For this situation, we immediately began to request token and refresh token, the second validity period is unlimited and we can publish videos even after 60 minutes.
Corrected mistakes:
In more detail what is token and refresh token and how to use them is in the manual, but here there are things that did not work exactly as described.
1. The very first difficulty: the token received on the device was invalid when used on the server.
In the end, decided like this
On Android, we use:
Intent intent = new Intent(...); intent.setData(Uri.parse("https://accounts.google.com/o/oauth2/auth?"+ "scope= " + scope + "&" + "redirect_uri=" + redirect_uri + "&" + "response_type=" + response_type + "&" + "client_id=" + client_id)); startActivityForResult(intent);
As a result, we get an authorization code, then we get token and refresh token ourselves
HttpPosthttppost = newHttpPost("https://accounts.google.com/o/oauth2/token"); httppost.setHeader("Content-Type", "application/x-www-form-urlencoded"); List<NameValuePair>nameValuePairs = newArrayList<NameValuePair>(); nameValuePairs.add(newBasicNameValuePair("code", code)); nameValuePairs.add(newBasicNameValuePair("client_id", client_id)); nameValuePairs.add(newBasicNameValuePair("redirect_uri", redirect_uri)); nameValuePairs.add(newBasicNameValuePair("grant_type", "authorization_code")); httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); HttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent())); String responseLines; while ((line = reader.readLine()) != null) { responseLines += line; } JSONObject jsonObject = new JSONObject(responseLines);
As a result, we get a response of the form:
{ "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", "expires_in":3920, "token_type":"Bearer", "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
Get the token and refresh token and send them to the server
On the server side:
To check the validity of the token:
var verificationUri = "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + youTubeToken; var hc = new HttpClient(); var response = hc.GetAsync(verificationUri).Result; string tokenInfo = response.Content.ReadAsStringAsync().Result; JsonTextParser parse = new JsonTextParser(); JsonObject jsonObj = parse.Parse(tokenInfo);
As a result, we get a response of the form:
{ "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", "expires_in":320, "token_type":"Bearer" }
If the token's lifetime is enough, then use it, if not, then we get a new token, use the refresh token:
WebClient client = new WebClient(); NameValueCollectionloginFormValues = newNameValueCollection(); loginFormValues.Add("client_id", client_id); loginFormValues.Add("refresh_token", refreshYouTubeToken); loginFormValues.Add("grant_type", "refresh_token"); Byte[] response = client.UploadValues("https://accounts.google.com/o/oauth2/token", loginFormValues); string result = Encoding.UTF8.GetString(response); JsonTextParser parse = newJsonTextParser(); JsonObjectjsonObj = parse.Parse(result);
As a result, we get a response of the form:
{ "access_token":"1/fFBGRNJru1FQd44AzqT3Zg", "expires_in":3600, "token_type":"Bearer", }
Use the received token for its intended purpose.
2. Further, the parameters "scope", "state" and "client_secret": in some cases, where according to the documentation these parameters must be specified, the program gave an error if we set them, and worked fine if not set. And vice versa - sometimes they had to be used not only where indicated.
')
For example, the “state” parameter often returns a value in the form of the nearest US state where the Google server is located — this increases the speed of data exchange between the server and the device. In some cases, this parameter is specified as mandatory. But in Russia it is useless.
“Scope” is responsible for which service we want to use when accessing Google. It is not clear where to get the full list of values for this parameter. Since we needed YouTube, we, having indicated it, simply guessed. At the same time, it is not clear what parameter value should be if we want to refer, for example, to the Google calendar?
In one of Google’s documentation requests, the client_secret parameter is needed. We don't have it. And if we receive and specify - nothing works.
3. Most of our application is done on a webserver. But when requesting a token, the webserver was not valid, so we applied installedapps and requests approached it. To be honest, they did not understand why.
4. The
developers.google.com/accounts/docs/OAuth2InstalledApp#formingtheurl documentation lists two possible options for the redirect_uri parameter: “urn: ietf: wg: oauth: 2.0: oob” and
localhost . How to use
localhost , it was not clear to me, with “urn: ietf: wg: oauth: 2.0: oob” everything worked.
5. Also open is the question of how to use the token obtained from the Android account on the device itself. Those. An account is linked to Android, and it is from this account that you can get a token, but it is unclear how to use it. We use what we request from the user account.
6. It is not clear yet what scope should be used for “logging in to your GOOGLE account”? We use "to control YouTube".
7. And I wonder why the Google Library for OAUTH2 Android weighs so much? Using it, our application becomes several times harder, so we refused to use it.
Thanks for attention! I would be glad if someone will help my comments, as well as if someone can answer my questions.