gmusic.api icon indicating copy to clipboard operation
gmusic.api copied to clipboard

Authentication Question

Open milleph opened this issue 12 years ago • 25 comments

I'm integrating your library with my current app which already uses the Android AccountManager for authentication with an App Engine (GAE) server.

The authtoken obtained for the GAE is fetched as follows

    accountManager.getAuthToken(account, "ah", false, new GetAuthTokenCallback(), null);

Where "ah" is the authTokenType for App Engine. Other types are "youtube", "finance" etc for the different apis.

So here's my question... Is it possible to obtain a token this way for gmusic.api and avoid the need to user to enter their password? If so, what authTokenType should be used?

milleph avatar Jan 31 '13 15:01 milleph

You can obtain auth Token so:

accountManager.getAuthToken(account, "sj", null, this, new AccountManagerCallback() {
            @Override
            public void run(AccountManagerFuture result) {
                // Get the result of the operation from the AccountManagerFuture.
                Bundle bundle;
                try {
                    bundle = result.getResult();
                    // The token is a named value in the bundle. The name of the value
                    // is stored in the constant AccountManager.KEY_AUTHTOKEN.
                    Token=bundle.getString(AccountManager.KEY_AUTHTOKEN);

dommy1985 avatar Jan 31 '13 16:01 dommy1985

Perfect! I will try it later - many thx.

milleph avatar Jan 31 '13 16:01 milleph

Awesome - please post a fully example using both the Account Manager and use of the Google Music API

jkiddo avatar Jan 31 '13 19:01 jkiddo

I can confirm it works and will post example when the day job is done

milleph avatar Feb 01 '13 12:02 milleph

Any progress on the example by any chance?

SnoochieBoochies avatar Mar 03 '13 19:03 SnoochieBoochies

@milleph would you be kind enough to post it?

jkiddo avatar Mar 03 '13 20:03 jkiddo

It's very easy with Google Play services , you must only add google-play-services.jar and use this code : token = GoogleAuthUtil.getToken( mActivity, mEmail, "sj"); it's only supported to real devices , no emulator

dommy1985 avatar Mar 05 '13 09:03 dommy1985

The two examples posted by @dommy1985 show you how to get the token. By far, the simplest way is by using the Google Play Services jar in his second example. In either case, there are some traps that are best handled in the implementing application, instead of within the gm library. Be sure to read up on using the Play Services jar here:

http://android-developers.blogspot.com/2012/09/google-play-services-and-oauth-identity.html

Google has not yet exposed the Music service through the Google Oauth API, so you can't use the Oauth examples in the article, but the details (responses and handling) are still helpful.

For now, I'll modify the android.gm library so you can pass the token to it and login with it.

bkhall avatar Mar 12 '13 16:03 bkhall

Here is an example of how to use the new login method.

In your application, extend AsyncTask to get the token and pass it to the new gm library login method:

public class GoogleAuthTask extends AsyncTask<String, Void, Boolean> {

    private Activity mActivity;

    public GoogleAuthTask(Activity activity) {
        mActivity = activity;
    }

    @Override
    protected Boolean doInBackground(String... params) {
        boolean success = false;
        try {
            String authToken = GoogleAuthUtil.getToken(mActivity, params[0],
                    "sj");

            if (!TextUtils.isEmpty(authToken)) {
                GoogleMusicApi.createInstance(mActivity);

                success = GoogleMusicApi.login(mActivity, authToken);

                if (!success)
                    GoogleAuthUtil.invalidateToken(mActivity, authToken); 
            }
        } catch (UserRecoverableAuthException e) {
            mActivity.startActivityForResult(e.getIntent(), 1001);
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (GoogleAuthException e) {
            e.printStackTrace();
        }

        return success;
    }
}

Also in your application/activity, execute the above task where necessary, like this:

GoogleAuthTask task = new GoogleAuthTask(this) {
    @Override
    protected void onPostExecute(Boolean success) {
        Toast.makeText(MainActivity.this, String.valueOf(success),
                Toast.LENGTH_LONG).show();
    }
};
task.execute([your_email_address]);
// there must be a google account on the device that uses this same email address.

bkhall avatar Mar 12 '13 17:03 bkhall

Great @bkhall , You must also make this:

//if GoogleMusicApi.login(mActivity, authToken); return Error 401 
GoogleAuthUtil.invalidateToken(mActivity, token); 

this is necessary to invalidate the old token is being assigned a new token

dommy1985 avatar Mar 12 '13 17:03 dommy1985

Great comment. Updated the example...

bkhall avatar Mar 12 '13 18:03 bkhall

@dommy1985 How do I check if 401 is returned? GoogleMusicApi.login() seems to always return true, if the token isn't empty.

cypressious avatar Oct 26 '13 15:10 cypressious

You’ll have to build out your own class/method to do that from the source code in the project. At the time, all I cared about was whether or not the login succeeded.

At the point where the request returns an HttpResponse call the httpResponse.getStatusLine().getStatusCode() method. That’ll give you what you’re looking for. If the statusCode == HttpStatus.SC_OK, then continue. You could wrap the cases in a switch-case block to handle the different statusCodes.

From: cypressious [mailto:[email protected]] Sent: Saturday, October 26, 2013 10:04 AM To: jkiddo/gmusic.api Cc: Baron Hall Subject: Re: [gmusic.api] Authentication Question (#5)

@dommy1985 https://github.com/dommy1985 How do I check if 401 is returned? GoogleMusicApi.login() seems to always return true, if the token isn't empty.

— Reply to this email directly or view it on GitHub https://github.com/jkiddo/gmusic.api/issues/5#issuecomment-27148057 . https://github.com/notifications/beacon/ydqSPYcpm3TVNpQocQzaUqVIlTOmhEt-V9_ohJ8yTLoUDJWJf8v3PhRuineGu9UF.gif

bkhall avatar Oct 26 '13 17:10 bkhall

Thanks for responding. I modified the login() method to look like this:

public static final boolean login(final Context context,
        final String authToken) {
    if (!TextUtils.isEmpty(authToken)) {
        final SimpleForm form = new SimpleForm().close();
        GoogleMusicApi.setAuthorizationHeader(authToken);
        mHttpClient.post(context,
                "https://play.google.com/music/listen?hl=en&u=0",
                new ByteArrayEntity(form.toString().getBytes()),
                form.getContentType());

        return mHttpClient.getResponseCode() == HttpStatus.SC_OK;

    } else {
        return false;
    }
}

cypressious avatar Oct 26 '13 17:10 cypressious

Its a matter of code style - the desktop API version implements the login method as void - and throws exceptions for anything else than OK. And btw - the desktop API version also works on android

jkiddo avatar Oct 26 '13 22:10 jkiddo

I tried to login using following method but the response code given was 200 :

public static final boolean login(final Context context, final String authToken) { if (!TextUtils.isEmpty(authToken)) {

     final SimpleForm form = new SimpleForm().close();

     GoogleMusicApi.setAuthorizationHeader(authToken);

     String response = mHttpClient.post(context, "https://play.google.com/music/listen?hl=en&u=0", new  ByteArrayEntity(form.toString().getBytes()), form.getContentType());

    Log.d(TAG, "response = " + response);
    Log.d(TAG, "mHttpClient.getResponseCode() " + mHttpClient.getResponseCode());

    return mHttpClient.getResponseCode() == HttpStatus.SC_OK;

  } else {
    return false;
  }

}

and I got response like this :

12-11 17:55:03.785: D/com.android.gm.api.GoogleMusicApi(24744): response = Google Play Music#gb{font:13px/27px Arial,sans-serif;height:30px}#gbz,#gbg{position:absolute;white-space:nowrap;top:0;height:30px;z-index:1000}#gbz{left:0;padding-left:4px}#gbg{right:0;padding-right:5px}#gbs{background:transparent;position:absolute;top:-999px;visibility:hidden;z-index:998;right:0}.gbto #gbs{background:#fff}#gbx3,#gbx4{background-color:#2d2d2d;background-image:none;background-image:none;background-position:0 -138px;background-repeat:repeat-x;border-bottom:1px solid #000;font-size:24px;height:29px;height:30px;opacity:1;filter:alpha(opacity=100);position:absolute;top:0;width:100%;z-index:990}#gbx3{left:0}#gbx4{right:0}#gbb{position:relative}#gbbw{left:0;position:absolute;top:30px;width:100%}.gbtcb{position:absolute;visibility:hidden}#gbz .gbtcb{right:0}#gbg .gbtcb{left:0}.gbxx{display:none !important}.gbxo{opacity:0 !important;filter:alpha(opacity=0) !important}.gbm{position:absolute;z-index:999;top:-999px;visibility:hidden;text-align:left;border:1px solid #bebebe;background:#fff;-moz-box-shadow:-1px 1px 1px rgba(0,0,0,.2);-webkit-box-shadow:0 2px 4px rgba(0,0,0,.2);box-shadow:0 2px 4px rgba(0,0,0,.2)}.gbrtl .gbm{-moz-box-shadow:1px 1px 1px rgba(0,0,0,.2)}.gbto .gbm,.gbto #gbs{top:29px;visibility:visible}#gbz .gbm{left:0}#gbg .gbm{right:0}.gbxms{background-color:#ccc;display:block;position:absolute;z-index:1;top:-1px;left:-2px;right:-2px;bottom:-2px;opacity:.4;-moz-border-radius:3px;filter:progid:DXImageTransform.Microsoft.Blur(pixelradius=5);opacity:1;top:-2px;left:-5px;right:5px;bottom:4px;-ms-filter:"progid:DXImageTransform.Microsoft.Blur(pixelradius=5)";opacity:1\0/;top:-4px\0/;left:-6px\0/;right:5px\0/;bottom:4px\0/}.gbma{position:relative;top:-1px;border-style:solid dashed dashed;border-color:transparent;border-top-color:#c0c0c0;display:-moz-inline-box;display:inline-block;font-size:0;height:0;line-height:0;width:0;border-width:3px 3px 0;padding-top:1px;left:4px}#gbztms1,#gbi4m1,#gbi4s,#gbi4t{zoom:1}.gbtc,.gbmc,.gbmcc{display:block;list-style:none;margin:0;padding:0}.gbmc{background:#fff;padding:10px 0;position:relative;z-index:2;zoom:1}.gbt{position:relative;display:-moz-inline-box;display:inline-block;line-height:27px;padding:0;vertical-align:top}.gbt{display:inline}.gbto{box-shadow:0 2px 4px rgba(0,0,0,.2);-moz-box-shadow:0 2px 4px rgba(0,0,0,.2);-webkit-box-shadow:0 2px 4px rgba(0,0,0,.2)}.gbzt,.gbgt{cursor:pointer;display:block;text-decoration:none !important}span#gbg6,span#gbg4{cursor:default}.gbts{border-left:1px solid transparent;border-right:1px solid transparent;display:block;display:inline-block;padding:0 5px;position:relative;z-index:1000}.gbts{display:inline}.gbzt .gbts{display:inline;zoom:1}.gbto .gbts{background:#fff;border-color:#bebebe;color:#36c;padding-bottom:1px;padding-top:2px}.gbz0l .gbts{color:#fff;font-weight:bold}.gbtsa{padding-right:9px}#gbz .gbzt,#gbz .gbgt,#gbg .gbgt{color:#ccc!important}.gbtb2{display:block;border-top:2px solid transparent}.gbto .gbzt .gbtb2,.gbto .gbgt .gbtb2{border-top-width:0}.gbtb .gbts{background:url(//ssl.gstatic.com/gb/images/b_8d5afc09.png);_background:url(//ssl.g

how to resolve this issue?

mithilwcities avatar Dec 11 '13 12:12 mithilwcities

The Android variant has been removed. Is there any way to login with a token?

Is this part of what needs to be implemented (cf. Readme)?

geecko86 avatar Mar 08 '15 06:03 geecko86

@geecko86 - the Android variant was more like a 'feature' branch. What kind of token do you mean? AFAIK, you can only login to the service using either regular password or the app specific 2-factor auth password. Currently, I think that the only part that works is actually login - everything else pretty much returns 404 - and I can't even say for how long it hasn't worked - probably as long back as 3 months

jkiddo avatar Mar 08 '15 07:03 jkiddo

And, for reference, the current API also works on Android, that is - until it the URL's were changed, which might be around July, 2014

jkiddo avatar Mar 08 '15 12:03 jkiddo

The feature I'm interested in (getAllSongs()) still works once logged in.

I'm talking about the type of authTokens referenced just above. The current API works on Android, yes, but the former Android variant featured a login(Context context, String token) method, which is why I was asking if it was still possible to login with a token and not just a password. You're saying it's not. Unless you have any objection I'll put it back in the code.

I'll also check out commits around July 2014 on Simon's repo. :)

geecko86 avatar Mar 08 '15 14:03 geecko86

It should still be possible...

If you login once with the username/password method, then cache the token securely somewhere, you can use that token here later, until it expires or it's revoked. In which case you'll have to go through the username/password login again.

However, if you have two-factor authentication turned on, the username/password login will fail. You'll either have to turn it off or create an application specific login in your Google account for Google Music.

Just Google around if you don't know how to do that.

I should also point out that this token is a web token. It's not the same token you get back if you're using Oauth for example, so don't bother with that. It simply won't work. On Mar 8, 2015 9:24 AM, "Guillaume" [email protected] wrote:

The feature I'm interested in (getAllSongs()) still works once logged in.

I'm talking about the type of authTokens https://github.com/jkiddo/gmusic.api/issues/5#issuecomment-12950840 referenced just above. The current API works on Android, yes, but it featured a login(Context context, String token) https://github.com/jkiddo/gmusic.api/blob/0323358eae008159690e47746a1a1d1aaa967947/android.gmusic.api/src/com/android/gm/api/GoogleMusicApi.java#L68 method, which is why I was asking if it was still possible to login with a token and not just a password. You're saying it's not. Unless you have any objection I'll put it back in the code.

I'll also check out commit around July 2014. :)

— Reply to this email directly or view it on GitHub https://github.com/jkiddo/gmusic.api/issues/5#issuecomment-77751553.

bkhall avatar Mar 08 '15 15:03 bkhall

You're welcome to introduce the dependency to Android again including the login, but as @bkhall says, its a web token.

jkiddo avatar Mar 08 '15 15:03 jkiddo

@geecko86 - I did some digging yesterday, and I don't think that the URL's have changed. I more seems like that the HTTP requests does not contain all the cookies that Google Music responds with. This is pretty clear if you use the Apache HTTP client instead of the HttpUrl client. @geecko86 Would you care to look into this?

jkiddo avatar Mar 12 '15 09:03 jkiddo

Even though I support the project and would like to see it flourish, I ended up finding a much more efficient way to list all the tracks from Google Play Music on Android.

On top of that, I'm afraid I'm not really qualified when it comes to network stuff... Sorry.

geecko86 avatar Mar 12 '15 09:03 geecko86

@geecko86 Could you share your "much more efficient way to list all the tracks from Google Play Music on Android"? I am not into cookies and http clients either :)

120015000388 avatar Mar 26 '15 21:03 120015000388