playgameservices / play-games-plugin-for-unity

Google Play Games plugin for Unity
Other
3.46k stars 967 forks source link

Accessing Auth Token? #10

Closed MrTinto closed 9 years ago

MrTinto commented 10 years ago

Is there any way to access the Auth Token that was used when authenticating the user? I need to use it to authenticate the user with my own server.

Disturbing commented 10 years ago

Agreed! I definitely need this as well.

Please implement auth token to be exposed to unity:

http://developer.android.com/google/play-services/auth.html

Thanks in advance!

MAW016 commented 10 years ago

Agreed as well!

makeshiftwings commented 10 years ago

Can someone please, please (PLEASE) offer some advice on how to access the auth token? Please?

repel commented 10 years ago

Pretty sure that isn't allowed per Google.

The Auth token would be useless because of the device which obtained it. To do what you want you must implement oauth2 on the Web server, request a server Api key then apply it to server. Make sure you server code request offline permissions for the user. Then setupa mysql server db to cache the token and then the refresh token, with that you can get some general info about the user to put in the database, like the email address which you could then cross reference from your Android appm to grant access into your website. Finally, within your application use a webview that doesn't leave your unity activity to display the Google login button on your sight with the proper redirects. Then close webview, and start having fun.

Atleast it how I did it. HopeThat helps

dgalpin commented 10 years ago

You technically can get the token through the Android GoogleAuthUtil if you really needed it, but you'd have to be careful about expiry, and you'd want to make sure that the scopes requested matched. You'd also have to add the GET_ACCOUNTS permission.

On Tue, Jun 10, 2014 at 8:52 PM, repel notifications@github.com wrote:

Pretty sure that isn't allowed per Google.

The Auth token would be useless because of the device which obtained it. To do what you want you must implement oauth2 on the Web server, request a server Api key then apply it to server. Make sure you server code request offline permissions for the user. Then setupa mysql server db to cache the token and then the refresh token, with that you can get some general info about the user to put in the database, like the email address which you could then cross reference from your Android appm to grant access into your website. Finally, within your application use a webview that doesn't leave your unity activity to display the Google login button on your sight with the proper redirects. Then close webview, and start having fun.

Atleast it how I did it. HopeThat helps

— Reply to this email directly or view it on GitHub https://github.com/playgameservices/play-games-plugin-for-unity/issues/10#issuecomment-45699166 .

repel commented 10 years ago

dgalpin, I believe their intentions is to incorporate and consume that auth token into a outside website. To do so according would require the infrastructure that I spoke of above to be in place to handle token refreshes, and all necessary access grants in place for both the android app and the web components. Yes, the token is available but pretty useless on its own.

metalize commented 10 years ago

I also need the OAuth token and I'm implementing a system quite similar to your description, @repel. I have all the infrastructure already, I just need the OAuth token from within Unity. Is there any way to get it from the plugin or will I need to write native code to do it? @dgalpin, is GoogleAuthUtil available from within the plugin? A grep through the source did not show any results.

tristan-fgol commented 9 years ago

+1 for AuthToken for server side authentication

samtstern commented 9 years ago

If you want to use the auth token from your Android/iOS Unity app on your web server (or anywhere off the original device) this is not a good idea. You shouldn't send auth tokens around, they are meant to be used by the client to which they were issued.

If you want to authorize your server to perform actions with Google APIs, you'll want to request a server auth code which your server can exchange for an offline access refresh token. The documentation for this process is here: https://developers.google.com/+/web/signin/server-side-flow

As others have mentioned on this thread, you'll have to go outside the Unity plugin (GoogleAuthUtil, etc) to make this work for now.

claywilkinson commented 9 years ago

tracking internally to expose client auth as 19126504

boudinov commented 9 years ago

Need that too please.

albertvaka commented 9 years ago

+1 :ok_woman:

boudinov commented 9 years ago

Found a way to get token with the Doge build (ver >= 0.9.10). First a problem is that that GoogleApiClient that is created internally in the C++ library, does not request Plus API. That client is obtained using (but we don't need it): JavaUtils.JavaObjectFromPointer(GooglePlayGames.Native.Cwrapper.InternalHooks.InternalHooks_GetApiClient(services.AsHandle()))

We need the client to request Plus api, because that is how we get the current Plus account (Plus.ApiAccount...). So we build a new client, and get the token as described in https://github.com/playgameservices/play-games-plugin-for-unity/issues/222

This new code is part of NativeClient class. The code while(!client.Call("isConnected")...sleep() should be run on another thread or in a coroutine, so UI thread is not get blocked until our new client is connected.

        private AndroidJavaObject GetApiClient(GameServices services) {
                    //return JavaUtils.JavaObjectFromPointer(GooglePlayGames.Native.Cwrapper.InternalHooks.InternalHooks_GetApiClient(services.AsHandle()));
                    using (var currentActivity = GetActivity()) {
                            using (AndroidJavaClass jc_plus = new AndroidJavaClass("com.google.android.gms.plus.Plus")) {
                                using (AndroidJavaObject jc_builder = new AndroidJavaObject("com.google.android.gms.common.api.GoogleApiClient$Builder",currentActivity)) {
                                            jc_builder.Call<AndroidJavaObject> ("addApi", jc_plus.GetStatic<AndroidJavaObject>("API"));
                                            jc_builder.Call<AndroidJavaObject> ("addScope", jc_plus.GetStatic<AndroidJavaObject>("SCOPE_PLUS_LOGIN"));
                                            AndroidJavaObject client = jc_builder.Call<AndroidJavaObject> ("build");
                                            client.Call ("connect");
                                            while(!client.Call<bool>("isConnected"))
                                            {
                                                    System.Threading.Thread.Sleep(100);
                                            }
                                            return client;
                                }
                            }
                    }
            }

            private string RetrieveUserEmail() {
                    string email;
                    using (AndroidJavaClass jc_plus = new AndroidJavaClass("com.google.android.gms.plus.Plus")) {
                            using (AndroidJavaObject jo_plusAccountApi = jc_plus.GetStatic<AndroidJavaObject>("AccountApi")) {
                                    Debug.Log("jo_plusAccountApi: " + (jo_plusAccountApi == null ? "NULL" : jo_plusAccountApi.ToString()));
                                    using (var apiClient = GetApiClient(mServices)) {
                                            Debug.Log("apiClient: " + (apiClient == null ? "NULL" : apiClient.ToString()));
                                            email  = jo_plusAccountApi.Call<string>("getAccountName", apiClient);
                                            Logger.d("Player email: " + email);
                                    }
                            }
                    }
                    return email;
            }

            public string GetToken() {
                    string token = null;
                    Debug.Log("Before RetrieveUserEmail");
                    string email = RetrieveUserEmail() ?? "NULL";
                    Debug.Log("After RetrieveUserEmail email: " + email);
                    string scope = "audience:server:client_id:" + "101626759741-kc5sdafasdfsdf9j1aek9bfgfou3oom.apps.googleusercontent.com";//CLIENT_ID;
                    using (AndroidJavaClass jc_unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"),
                           jc_gau = new AndroidJavaClass("com.google.android.gms.auth.GoogleAuthUtil")) {
                            using(AndroidJavaObject jo_Activity = jc_unityPlayer.GetStatic<AndroidJavaObject>("currentActivity")) {
                                    token = jc_gau.CallStatic<string>("getToken", jo_Activity, email, scope);
                            }
                    }
                    Debug.Log("Token " + token);
                    return token;
            }

This gets an ID Token (Java web token). A normal access token can be obtained by replacing scope (audience:server:client_id:....) with something like(https://www.googleapis.com/auth/plus.login)

A side note, can some scholarly guy tell is if we are in a very wrong direction, trying to get an access token this way, and that is why there is no built-in support for this in the Unity Plugin?

Boogscraft commented 9 years ago

Thank you boudinov, the ID token is exactly what I need (and I suspect most people here) to implement this flow: http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html

claywilkinson commented 9 years ago

@boudinov - at first glance this looks great! Do you think you can create a pull request so it can be looked at a little more closely and then become part of the plugin?

zindonx commented 9 years ago

i make all the stuff, that is described here and always get AndroidJavaException: com.google.android.gms.auth.UserRecoverableAuthException: NeedPermission.

Any suggestion?

Best regards.

JohnTube commented 9 years ago

@zindonx

Comments regarding this Exception thrown by GoogleAuthUtil.getToken

catch (UserRecoverableAuthException e) {
  // Requesting an authorization code will always throw
  // UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
  // because the user must consent to offline access to their data.  After
  // consent is granted control is returned to your activity in onActivityResult
  // and the second call to GoogleAuthUtil.getToken will succeed.
  startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
  return;
} 

source more details here

ccthien commented 9 years ago

Do we have any update? Anyone know the reason why this is not implemented until now?

ZenithCode commented 9 years ago

@claywilkinson @ccthien - This would be really nice to have for us too. An ETA would be nice! :+1:

illa3d commented 9 years ago

So, is there any working method of obtaining google login token on client side? Anyone? bump

seaders commented 9 years ago

@claywilkinson Please give us an update on this, as it would be a great improvement on what we need to do. While what @boudinov has done is great (and it really is), that's Android only, and definitely "feels" a little hacky, especially the way some of the grabbing and building the client is done, especially if that part (apparently) is already done.

With Google supporting the whole OpenID single-signon stance, and how widely it's used everywhere, I'm still at odds how it wasn't intrinsically part of the whole project, but now the you started talking about this way back in January 23rd, but while there have been recent commits, you haven't responded to this thread since 5th February!

C'mon guys, it really doesn't seem like it should be that big a deal and if you support devs getting access tokens on Android and iOS native, we should be able to get them via SDKs like this.

spacetraveller commented 9 years ago

What's the go with this ? This is seriously needed and is a huge block.

What if we need to do API calls that are outside of the PGS plugin ? It's impossible. I don't like being tied in, and this is making it necessary to use third party apps that Google does not recommend. Catch-22... Please Google, fix it!

ccthien commented 9 years ago

Make your own java plugin (like people above already mentioned)... or I have permission to contribute on this source.

spacetraveller commented 9 years ago

ccthien that is not a good solution. Google should implement this feature that is the reason for this issue, that is a very roundabout, hacky sort of way and who knows how long before that breaks.

ccthien commented 9 years ago

It is not a hack way. It is what we done on Java, with official play-game-services.jar lib (that they did not implement on this).

tristan-fgol commented 9 years ago

I really need this for both Android and iOS the example provided @boudinov is great for android and we have forked and taken advantage of that but I really need a cross platform way of doing this! Unless someone else has an iOS example as well?

seaders commented 9 years ago

@ccthien it is a hack, because it's not in the main repository, nor fully tested by the official providers (Google). It's also, as @tristan-fgol has said, not cross platform as in iOS,

- (void)finishedWithAuth: (GTMOAuth2Authentication *)auth
                   error: (NSError *) error
{
    NSLog(@"Received id_token %@ and email %@",
          [auth.parameters objectForKey:@"id_token"],
          [auth.parameters objectForKey:@"email"]);
}

You can only have access to the token in the Authentication flow after a successful login.

Not fully tested, not in the repository, not a full implementation. A hack by any other name.

ccthien commented 9 years ago

Hack & official is difference on who made it. I made some apps that users usually reported that it is better than official one (even if the official one is free and mine is paid).

illa3d commented 9 years ago

Bump! Does anyone know an effective "workaround" how to get an user's google play acces token for that specific app from a frontend (for backend user check towars google again) on both iOS and Android platforms?

Thanks in advance guys!

spacetraveller commented 9 years ago

Maybe somebody with a bit of time could write a simple plugin to get this data out of the GPG plugin? (If you're keen, how about creating a repo in github for it?) As it doesn't appear GPGS are going to update their plugin anytime soon with our requests?

Another thing that is very much missing is being able to obtain a registration ID for the app on the Android device - this is necessary for push notifications if you are interfacing with a third party server or your own server.

JurjenBiewenga commented 9 years ago

+1

bursaar commented 9 years ago

+1, this'd be a lifesaver!

daveor2112 commented 9 years ago

+1 would be great

CormacM commented 9 years ago

+1 this would be really useful

ShaneOBrien commented 9 years ago

+1 would make life easier

podonne5 commented 9 years ago

+1 a necessity for our game

halloranjohn commented 9 years ago

+1 please add this.

Richief88 commented 9 years ago

+1 this is what we need to happen!

AuctrixAdmin commented 9 years ago

+1 for this. Please implement.

lnobad commented 9 years ago

+1, please add this.

VladimirKuznetsov commented 9 years ago

+1

claywilkinson commented 9 years ago

awesome community participation! clearly this is the top priority! :)

seaders commented 9 years ago

Hey Clayton, after seeing this thread, http://forum.unity3d.com/threads/google-play-games-login-guide.320187/ on the Unity forum a few days ago, I started poking around with this again and learned that idToken is now exposed from the GPPSignIn singleton on iOS. Because of this, it's as easy as anything to now get the access token, it's not just available to you during the login flow any more. That definitely wasn't around when this thread started, but 100% is now.

With that, I actually went through creating a pull request implementing that, bringing the WebView in from that thread as well (because some apps were getting rejected from it), and the Android GetToken posted in this thread. Will have a pull request ready for you to hopefully review today, as well as a patch for anyone who may want to just apply it to their project.

Thanks for getting back to us on this, though. The biggest frustration was that the services offered in this plugin really are awesome, but then being unable to use this and them because of just this issue.

seaders commented 9 years ago

And there we go, pull request is in for you @claywilkinson, https://github.com/playgameservices/play-games-plugin-for-unity/pull/641

And for anyone who wants this, but don't want to wait for the merge & creation of the .unitypackage, here's a patchfile, https://gist.github.com/seaders/9786b9372023af87b1c3#file-tokenpatch-patch which, after installing the 0.9.21 .unitypackage, you can apply simply with git tokenPatch.patch in the root directory of your project.

Happy access tokening!

JohnTube commented 9 years ago

@seaders thanks for your efforts. I just want to check if your changes are "officially" done and live. And I have also noticed that you used @boudinov code snippet above to get token for Android but you kept it as is without moving the while(!client.Call("isConnected")...sleep() block to a separate background thread to avoid blocking the main UI thread ! This was a recommendation of the original author of the code. So is it safe this way ?

seaders commented 9 years ago

@claywilkinson has merged it into the official repo, so it's in there, under source/PluginDev and he's said he'll publish the .unitypackage after he gets a few other things in. As for that suggestion, all calls that may use GetApiClient (it's private) are wrapped with if (!this.IsAuthenticated()), https://github.com/SixMinute/play-games-plugin-for-unity/commit/94973532833a1567901a9db4aa1296da6749d309.

I'm going to assume that this will get redesigned, exposing more of the native builder options maybe, when they get a chance (I think a new big-ish release may be coming in September), but for the moment, you can't add the api and scope any other way, kinda. Ensuring that there's already a client that is connected basically means there's nearly no chance of it locking up, unless you enter some sort of weird edge condition.

It's not perfect, and will get better, I know that, but for the moment, if not being able to get the access token was a blocker, it no longer has to be.

Also, on the blocking nature of the call, you are in control of how you get that, so in your code, you could choose to put it behind a Coroutine if you're worried, but I honestly don't think it's that necessary.

JohnTube commented 9 years ago

@seaders thanks for the clarifications. I think that I will keep using my own Google+ Unity plugin available here as a 3rd party plugin (see Readme).

illa3d commented 9 years ago

Do you have any rough estimate when the .unitypackage will be released with the auth token implementation?

Thanks a bunch for this update @seaders! /dances

claywilkinson commented 9 years ago

Added this afternoon - if you pull the latest unitypackage it is there.

illa3d commented 9 years ago

@claywilkinson thank you!