I use the following to get an authentication that I can access a backend from an Android app. This is described here https://developers.google.com/identity/protocols/CrossClientAuth.
StringBuffer sb = new StringBuffer();
sb.append("oauth2:server:client_id:");
sb.append(getString(R.string.google_app_id));
sb.append(":api_scope:");
sb.append("profile email");
final String scope = sb.toString();
String token = GoogleAuthUtil.getToken(Activity.this, mAuthAccount, scope);
(mAuthAccount was previously set using AccountPicker.newChooseAccountIntent.)
The above returns a short lived authentication code which sometimes has expired. I would like to check it against google servers, but calling https://www.googleapis.com/oauth2/v1/tokeninfo?access_token= with the returned token string from GoogleAuthUtil.getToken returns "invalid token".
How do I verify that the authentication code has not expired before I try to use it?
Edit: The returned string is not a token, but an authorization code which can be exchanged with a google API to obtain a token (The returned string begins with "/4" and not "/1" or "/2" if I remember correctly).
The code does not always work (on my server) and I would love to be able to check if the code can be used or has expired.
You don't need to use app_id to get oauth token, You just need to change scope
"oauth2:" + Scopes.PLUS_LOGIN
In this case your scope can be plus.login
More Info:
Authorizing with Google for REST APIs
Scopes Class
As you can see in Validating the token documentation:
https://www.googleapis.com/oauth2/v1/tokeninfo
Accepts an access token and returns information about that access
token including which application was it issued to, the intended
target of the token, the scopes the user consented to, the remaining
lifetime of the token, and the user ID.
Below is an example of such a request:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=1/fFBGRNJru1FQd44AzqT3Zg
The TokenInfo endpoint will respond with a JSON array that describes the token or an error.
On the wire, the response looks similar to the following:
{
"audience":"8819981768.apps.googleusercontent.com",
"user_id":"123456789",
"scope":"profile email",
"expires_in":436
}
If the token has expired, has been tampered with, or the permissions
revoked, the Google Authorization Server will respond with an error.
The error surfaces as a 400 status code, and a JSON body as follows:
{"error":"invalid_token"}
By design, no additional information is given as to the reason for the failure.
So invalid_token is a valid answer when the token has expired, has been tampered with, or the permissions revoked
EDIT
It is possible to receive invalid_token just after the token is returned from GoogleAuthUtil.getToken because GoogleAuthUtil may have cached it. In this case you should call GoogleAuthUtil.invalidateToken.
You can find more information here:
http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html
EDIT 2
I just notice that you are missing https://www.googleapis.com/auth/plus.login in your scope. Please try to add it because seems mandatory to use Cross-client Identity.
The token retrieved by GoogleAuthUtil.getToken() in this fashion is not an access token, it's an ID token.
Try the following URL instead (note id_token query parameter instead of access_token):
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=<ID TOKEN>
Related
I am using retrofit 2.0 to build a Bitbucket REST client on Android.
As far as I'm concerned, OAUTH2.0 provides "Implicit grant" which gives the client the access Bearer token immediately when the user logins to their account when are prompted to.
Bearer tokens are tokens that can be used to access protected resource. Anyone who has a bearer token has the permission to access the protected resource as anyone else who also has the bearer token. (according to this doc from IETF)
Please correct me if I'm wrong, but I thought using implicit grant, after user logins in their Bitbucket account, I will have the Bearer access token. After that, I can use this access token to access protected resource on Bitbucket (like create a new repository).
So I have built my android using the OAUTH2.0 Implicit grant as described in the Bitbucket doc. Note that they described the response will have #access_token={token}&token_type=bearer
And this is what I actually received from Bitbucket after logging in:
your://redirecturi#access_token=lEuvneW39onVrnNR-jvZfirI43fwi5Wdc0YaaMROBk5YKJsd2ulXm20vJDdOBjf8I-Ne2r2vC8-_FHECSLw%3D&scopes=pipeline%3Awrite+webhook+snippet%3Awrite+wiki+issue%3Awrite+pullrequest%3Awrite+repository%3Adelete+repository%3Aadmin+project%3Awrite+team%3Awrite+account&expires_in=3600&token_type=bearer
My first question:
What exactly is the Bearer access token from the above response?
Is the part lEuvneW39onVrnNR-jvZfirI43fwi5Wdc0YaaMROBk5YKJsd2ulXm20vJDdOBjf8I-Ne2r2vC8-_FHECSLw the Bearer access token? Do I have to include the "%3D" (which is the char "=" encoded in ASCII)? Doesn't the Bitbucket doc mean that everything exceptfor the last "&token_type=bear" is the Bear access token?
That's not all. Bitbucket doc's instruction to make request as follow:
Send it in a request header: Authorization: Bearer {access_token}
So I set this request up to create a new repository in accordance with the API of Bitbucket:
#POST("repositories/{username}/{repo_slug}")
Call<Repository> createRepository(
#Header("Authorization") String auth,
#Path("username") String userName,
#Path("repo_slug") String repoSlug);
But everytime, I got the respones with status code 401 and message error:
Access token expired. Use your refresh token to obtain a new access token.
When I tried to POST the same request using DHC by Restlet (a chrome extention like Postman), a pop up appears and requires me to login to Bitbucket. If I refuse to do so, I got the same error 401 response. If I do login, then it works.
My second question: Why do I have to provide my credentials again?
I think there's something wrong here. I thought with the Bearer access token, I should be able to access the protected resource without having to log in before the access token's expire time has been reached. Why do I have to enter my credentials the second time? This is not what is described in the "Implicit grant" approach here by IETF.
The value of the access_token starts after access_token= and ends before the next parameter scopes so before &scopes=. The formatting of the fragment part is specified in https://www.rfc-editor.org/rfc/rfc6749#section-4.2.2 which in its turn points to https://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#h-17.13.4.1 which says:
[...] The name is separated from the value by = and name/value pairs
are separated from each other by & [...]
So your access token value by spec is lEuvneW39onVrnNR-jvZfirI43fwi5Wdc0YaaMROBk5YKJsd2ulXm20vJDdOBjf8I-Ne2r2vC8-_FHECSLw%3D but I agree that the ending %3D is suspicious and may be an error on the sender's part.
If your access token is expired (which is what it seems to be) you need to get a new one using the Implicit grant again, or using the Refresh token grant.
I am trying to implement Google Sign in OAuth 2.0, but I have inquiry why the token returned from the method getIdToken() is very too long such as the following:
eyJhbGciOiJSUzI1NiIsImtpZCI6ImQ1ZWViYzRjOWY5NGVkMzVhYWE5YTdiZTUyYzM0YTNmZDUwZGQ4ODkifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiI1NTc5ODE0OTE1NDItc3RkcGEwY3JmOWNvMXBvNW1pZW9pczEyZG1wcnJzcDQuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDM2MjY1NDEwNDQxOTYxNTY5NjEiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiNTU3OTgxNDkxNTQyLWoxdW5zZThhbmNtY2E2NzVnaW1hbWwzaDRpYzFwMnI2LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJtYWhtb3VkLmlicmFoaW0wMTZAZ21haWwuY29tIiwiaWF0IjoxNDY1MTQxNTMwLCJleHAiOjE0NjUxNDUxMzAsIm5hbWUiOiJNYWhtb3VkIElicmFoaW0iLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDQuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1PTGZKM1JKazFjYy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFCNC83anpkeTZnVkdwUS9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiTWFobW91ZCIsImZhbWlseV9uYW1lIjoiSWJyYWhpbSIsImxvY2FsZSI6ImVuIn0.FCsDYU7S8TEKrbm6VxBVXaJlLzrzPuXTP_z14RMIzMZohWNOpHwLYFQivkzy1mC6KJ67qECv0MI5Ap14R2vkxr7XtU9dyZH6oWBvDOgW6KYyBazEi5214Rp-uUeFXDEDFIY_mSOaS0mjlU8N9UxZfr4zIRY6R1p2JI4l1RWOb_rid8bT4gNpA6LFeop9BtmaOeSSuOfmLheqw5Uz3Ws2WCGdu857-rTZc3W5ywfbckvkZN72CRgrKUAeRbcHuGndX83NRpBFdHChXr4FIVT3tWWjiMRsCxLTvDNxXClV269IP9tXELhqNBACdPEX60hRX-DgXPSGl9SQ85IY090nuQ
Google Signin produces a compact serialized JSON Web Token (JWT, https://www.rfc-editor.org/rfc/rfc7519) to represent the authenticated user. That token is self-contained and contains information about the user in a verifiable way. You can verify that your token is a valid JWT at: http://jwt.io So yes, it is a valid token and it gets very large as more information is embedded in it.
I'm using GoogleAuthUtil in Google Play Services on Android. After calling GoogleAuthUtil.getToken(context, userName, scope), I got a token like this:
ya29.wQBWztab5kcgMLcMbAI0LwFzHC_DPrxauSWbX4P6KOnBEOgjcm9V7OI9AFr6JGxDY54gP00RemzzgML56_gWRHn8Q5jK16BLY-0y83Gc5vfe3xN-QpyM4d7z
This is an access_token, which can be used in calling Google Apis. Then, how can I get a refresh token to refresh this access_token, because I also use Google oauth java library and YouTube Java Library in my Android project, I want to use these two libraries to maintain/manage the access_token, refresh token and expires_in values. (When using Google oauth java library, the TokenResponse it returned contains access_token, refresh token and expires_in)
Thanks in advance.
You cannot directly get a refreshToken using GoogleAuthUtil.getToken() but if you call getToken() each time you get a 401 error, GoogleAuthUtil will return you a new valid token if needed.
In order to get a refresh token, make sure that your scope is in the following format:
Account account = new Account(mEmail, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
mScope="oauth2:server:client_id:"+ OAUTH_WEBCOMPONENT_ID+":api_scope:"+"https://www.googleapis.com/auth/userinfo.email";
return GoogleAuthUtil.getToken(mActivity, account, mScope);
This will give you an authorization code, which can be sent to your web component.
Your webcomponent than can use this authorization code only once to get an access token and refresh token with this code. You have to save the refresh token in your database, so that when the access code is no longer valid you can get a new access token when needed.
POST /oauth2/v3/token HTTP/1.1
Host: www.googleapis.com
Content-length: 233
content-type: application/x-www-form-urlencoded
user-agent: google-oauth-playground
code=4%2FVL2YMuPMheOP2-0vyKBSfGd-4er5GsMY17Ecp8ITK4U&redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&client_id=407408718192.apps.googleusercontent.com&client_secret=************&scope=&grant_type=authorization_code
You can simulate how this works here:
https://developers.google.com/oauthplayground/
Call requestServerAuthCode(String, true) instead requestServerAuthCode(String) which forces the request to include a refresh_token when it succeeds.
https://developers.google.com/android/reference/com/google/android/gms/auth/api/signin/GoogleSignInOptions.Builder.html#requestServerAuthCode(java.lang.String, boolean)
val task = GoogleSignIn.getSignedInAccountFromIntent(data);
task.addOnSuccessListener {
val account = task.getResult(ApiException::class.java)
val authCode = account!!.serverAuthCode
// Send authcode to server to exchange access and refresh tokens.
exchangeAuthCodeForAccessToken(authCode)
}
I'd like to get an access token without user login.
Standard way is that the user logs in and gets an access token.
But I need the access token to view events of an official page. When I try without access token, the Graph API gives me the following error:
{
"error": {
"message": "An access token is required to request this resource.",
"type": "OAuthException",
"code": 104
}
}
So my question: Is there any way to get an access token without explicitly logging in or is there maybe another way to get event information without access token?
Thanks so far :)
You can get the never-expiring-access-token for your page and use that with your call. (without explicitly logging, since you are the admin of the page). Follow the 2 steps: get the extended user (admin) token and then the never expiring page token
Extending the user's access token
You can exchange the user's access token with the long-lived access token (2-months) validity. Go though the link to get the long-lived token.
Extending tokens
Extending the page's access token
Make the following call using the long-lived user's access token and permission: manage_pages you obtained in the above step-
$facebook->api("/PAGE_ID?fields=access_token");
You'll get the never-expiring-page-token with this.
(You can use Facebook's Debug Tool to check the validity of the token)
Have a look at this site this websites talks all about Acess Tokens
Is it possible to authenticate the user on server side using auth token retrieved by Android applicaton from Facebook?
In other words Android application uses SSO and obtain auth token. Then sends this token to backend application deployed on Google App Engine. Then backend application verifies the user against Facebook using the token.
I guess it's not feasible because retrieved token can be used only by Android application, but who knows? Maybe it may be reused somehow?
The Token you get from Android API can be sent to your server, who can check the validity of the token by querying the graph ( using /me?auth_token=.... for example).
The problem is that the same token can be used by any third party - it's not client specific - and so if you base server identification based on that, you have a problem (since a third app could use its user token and get authenticated by you). I am trying to find a way to solve this issue, but I don't have good ideas yet...
Facebook actually has an Android SDK that lets you do this. Information can be found here.
Yes you can. A valid access token is a valid access token. The Graph API does from where the token came, but only that the token has the appropriate permissions to access that portion of the graph api. Keep in mind, though, that the token is only valid for 24 hours from the time of its issuance. (is that really a word?) From the time it is issued?
When using facebook android sdk with SingleSignOn (SSO), the access token format actually changed.
Instead of getting traditional auth token which contains userid & session key as a part of authToken
now we get a different format of authToken
As Facebook Devs are still in process to support there rest apis with newly formated access token
meanwhile we can disable the SSO on android facebook sdk by changing DEFAULT_AUTH_ACTIVITY_CODE to -1 from 32665 (in Facebook.java)
This will invoke Traditional dialouge for granting acess token and in return you'll get access token which will contain session key in it.
Those who are looking for generating secure session key you need to add your own method in Facebook.java like
public String getSessionSecret(String accessToken) throws MalformedURLException, IOException
{
Bundle b = new Bundle();
b.putString("method", "auth.promoteSession");
b.putString("access_token", accessToken);
b.putString("session_key_only", "true");
String response = request(b);
return response;
}