I can't find any solution for as i think very general issue...
I use google API for LogIn, and according to this article i can get tokenId using this method
private String getTokenId(GoogleSignInResult result) {
String tokenId = null;
GoogleSignInAccount googleSignInAccount = result.getSignInAccount();
if (googleSignInAccount != null) {
tokenId = googleSignInAccount.getIdToken();
}
return tokenId;
}
it is standard method, but why this method retern back token id which the contains 857 char of String? And i can't verify it with standard link
https://www.googleapis.com/oauth2/v3/tokeninfo?access_token= <857 char>;
and i get back this response
{
"error_description": "Invalid Value"
}
I am sure if google provide method to get token id there is have to be a method to verify it...
What am i doing wrong?
Related
I am following these instructions (https://developers.google.com/identity/sign-in/android/backend-auth) for getting an ID token to be sent to my Backend but when I set String scopes = "audience:server:client_id:" + Service.SERVER_CLIENT_ID; (Yes the SERVER_CLIENT_ID is not the Android Client ID) I fail to get a token and throws this error.
E/Login: com.google.android.gms.auth.GoogleAuthException: Unknown
However when I use the following scope instead
String scopes = "oauth2:profile email";
I successfully get 'a' token but it's not as long as I expected it to be and I'm afraid it might be wrong.
My questions are...
1) Why doesn't the scopes = "audience:server:client_id:" + SERVER_CLIENT_ID; used in the guide work?
2) Is the token I get from using String scopes = "oauth2:profile email"; a safe one for verifying a user on a Backend?
The code is below.
#Override
protected String doInBackground(Void... params) {
String accountName = Plus.AccountApi.getAccountName(googleApiClient);
Account account = new Account(accountName, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
//String scopes = "oauth2:profile email";
String scopes = "audience:server:client_id:" + Service.SERVER_CLIENT_ID; // Not the app's client ID.
Log.d(TAG, "Account Name: " + accountName);
Log.d(TAG, "Scopes: " + scopes);
try {
userIdToken = GoogleAuthUtil.getToken(getApplicationContext(), account, scopes);
return userIdToken;
} catch (IOException e) {
Log.e(TAG, "IOError retrieving ID token.", e);
return null;
} catch (UserRecoverableAuthException e) {
startActivityForResult(e.getIntent(), RC_SIGN_IN);
return null;
} catch (GoogleAuthException e) {
Log.e(TAG, "GoogleAuthError retrieving ID token.", e);
return null;
}
}
When you set the scope to oauth2:profile email you are returned an access token, which is different from an id token.
An access token can be used to access Google APIs, an id token is a JWT that contains identity information about the user that is digitally signed by Google. The formats are different. If you try to authorize an access token using the sample code provided for id tokens you'll get an invalid error.
If you look at the documentation for GoogleAuthUtil.getToken() you'll see that GoogleAuthException is a fatal exception usually caused by a client error such as invalid scope or invalid client.
https://developers.google.com/android/reference/com/google/android/gms/auth/GoogleAuthUtil#getToken(android.content.Context, android.accounts.Account, java.lang.String, android.os.Bundle)
Make sure that you have set up both an App and Webserver oAuth2 ID in Google Developer console and that the package name in your manifest matches the package name you provide along with the SHA fingerprint when creating the App ID. Use the Webserver ID as SERVER_CLIENT_ID.
I uploaded some sample code to Github. https://github.com/kmosdev/google-signin-backend-auth
I started with Google's sample sign-in app and modified it to add backend auth. Further details are in the Readme.
Another thing to check is that you have the correct permissions in your manifest file, but I believe you'd get a different error if this was wrong:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
I've been trying to set up a google login for my app.
I followed the tutorial here:
https://developers.google.com/identity/sign-in/android/start-integrating
I did everything. I can sign in sign in and sign out.
Then I added an Async task to get a token, which it seems to successfully retrieve. It is implemented as follows:
private class GetIdTokenTask extends AsyncTask<Void, Void, String> {
private static final String SERVER_CLIEdNT_ID = "749433126040-ca4gfj7ucuh0m2suo3230u03o3d7doni.apps.googleusercontent.com";
#Override
protected String doInBackground(Void... params) {
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
Account account = new Account(accountName, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
String scopes = "audience:server:client_id:" + SERVER_CLIEdNT_ID; // Not the app's client ID.
try {
return GoogleAuthUtil.getToken(getApplicationContext(), account, scopes);
} catch (IOException e) {
Log.e(TAG, "Error retrieving ID token.", e);
return null;
} catch (GoogleAuthException e) {
Log.e(TAG, "Error retrieving ID token. Google exception", e);
return null;
}
}
#Override
protected void onPostExecute(String result) {
Log.i(TAG, "ID token: " + result);
if (result != null) {
idToken = result;
Toast.makeText(context, "token is " + result, Toast.LENGTH_LONG).show();
} else {
// There was some error getting the ID Token
// ...
Toast.makeText(context, "token is null", Toast.LENGTH_LONG).show();
}
}
}
So after running the method and getting the token, I then run the generic firebase code to connect to Firebase (having already set up a google app, put the client ID in firebase, enabled it etc.) I got the code from https://www.firebase.com/docs/android/guide/login/google.html
And implemented it as follows:
public void loginFireBase() {
Firebase ref = new Firebase("https://boiling-fire-944.firebaseio.com");
ref.authWithOAuthToken("google", idToken, new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
// the Google user is now authenticated with your Firebase app
Toast.makeText(context, "user succesfully authenticated with firebase", Toast.LENGTH_LONG).show();
Toast.makeText(context, idToken, Toast.LENGTH_LONG).show();
}
#Override
public void onAuthenticationError(FirebaseError firebaseError) {
///////THIS IS THE PART WHERE THE ERROR IS GENEREATED FROM//////////
Log.v("firebase problem", firebaseError.toString());
Toast.makeText(context, "I'm an authenticated error" + "id Token was " + idToken, Toast.LENGTH_LONG).show();
}
});
}
}
So ultimately, I login, I get a token, and then pass it to the firebase authWithOAuthToken method, and then I get the error:
FirebaseError: Invalid authentication credentials provided.
Can anyone see any problems in my code? I have a feeling the token is not valid but can't find a way to check its validity.
Tell me if you need me to post more, I was trying to keep it brief.
Thanks to anybody who can help !
Whenever I need to authenticate with Firebase on Android, I go back to the Firebase Android login demo. Here's how that app gets the OAuth token for Google authentication:
String scope = String.format("oauth2:%s", Scopes.PLUS_LOGIN);
token = GoogleAuthUtil.getToken(
GoogleOAuthActivity.this,
Plus.AccountApi.getAccountName(mGoogleApiClient),
scope);
It looks like you're getting the cross-client id for the user, which is not a valid OAuth token.
Update (20160308): nowadays I instead look at the FirebaseUI library, which includes this functionality and is more up to date.
In my case i was having this error message in Firebase/Crash
the solution was run this line:
rm $HOME/Library/Preferences/com.google.SymbolUpload*
this was happening because previously already had generated the ServiceAccount.json file and restart the credentials needed
I'm using this ContainerRequestFilter to check HTTP Basic credentials.
private class Filter implements ResourceFilter, ContainerRequestFilter {
#Override
public ContainerRequest filter(ContainerRequest request) {
String auth = request.getHeaderValue("Authorization");
if (auth == null || !auth.startsWith("Basic ")) {
throw new NotAuthorizedException("FAILED\n");
}
auth = Base64.base64Decode(auth.substring("Basic ".length()));
String[] vals = auth.split(":");
String username = vals[0];
String password = vals[1];
boolean validUser = database.Users.validate(username, password);
if (!validUser) {
throw new NotAuthorizedException("FAILED\n");
}
return request;
}
...
}
So by the time I get to this point, I've authenticated the user. Now how I can get the username?
#GET
#Path("some_kind_of_report_or_something")
#Produces(MediaType.TEXT_PLAIN)
public String fetchAReportOrSomething() {
// At this point, I know that the user has provided good credentials,
// now I need get the user's username as a String
String username = ???;
}
I suppose I could use HttpContext.getRequest() and do the same thing as in the AuthFilter (I'd move that username/password extraction logic to its own method). In the filter, can I somehow store the extracted username somewhere in the request object so it gets passed on to this handler?
(By the way, is there a better way to extract the username and password than what I've done in the filter? If so, let me know in a comment.)
This blog entry should enlighten you:
http://plaincode.blogspot.pt/2011/07/openid-authentication-example-in-jersey.html
Take a look how it's done in a working application: www.s3auth.com. The source code is available at github. As you can see on the site, facebook and google authentication mechanisms are used. The application is using JAX-RS/Jersey.
I've been struggling with this for a couple days now. I'm trying to make calls to Google Calendar using authentication via Android's AccountManager. I retrieve an auth token using the usual method:
AccountManager manager = AccountManager.get(this);
String authToken = manager.getAuthToken(account, AUTH_TOKEN_TYPE, true, null, null).getResult().getString(AccountManager.KEY_AUTHTOKEN);
And then, with that token, I create a Calendar instance like this:
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JacksonFactory jsonFactory = new JacksonFactory();
GoogleAccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(accessToken);
Calendar calendar = Calendar.builder(transport, jsonFactory).setApplicationName("MyApp/1.0").setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
#Override
public void initialize(JsonHttpRequest request) {
CalendarRequest calendarRequest = (CalendarRequest) request;
calendarRequest.setKey(API_KEY);
}
}).setHttpRequestInitializer(accessProtectedResource).build();
However, when I make API calls using this, I receive the 401 Unauthorized error seen below. Note that I have included code to invalidate expired auth tokens, so I don't believe that's the problem here.
com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
"code" : 401,
"errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Invalid Credentials",
"reason" : "authError"
} ],
"message" : "Invalid Credentials"
}
Any thoughts on what I might be doing wrong?
Yes this is possible. Once you have a handle on the Google account (as you described), you just need to request an auth token from the AccountManager for the GData service.
If the android device already has an auth token (for the particular GData service you're trying to access), it will be returned to you. If not, the AccountManager will request one and return it to you. Either way, you don't need to worry about this as the AccountManager handles it.
In the following example, I am using the Google Spreadsheets API:
ArrayList<Account> googleAccounts = new ArrayList<Account>();
// Get all accounts
Account[] accounts = accountManager.getAccounts();
for(Account account : accounts) {
// Filter out the Google accounts
if(account.type.compareToIgnoreCase("com.google")) {
googleAccounts.add(account);
}
}
AccountManager accountManager = AccountManager.get(activity);
// Just for the example, I am using the first google account returned.
Account account = googleAccounts.get(0);
// "wise" = Google Spreadheets
AccountManagerFuture<Bundle> amf = accountManager.getAuthToken(account, "wise", null, activity, null, null);
try {
Bundle authTokenBundle = amf.getResult();
String authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
// do something with the token
InputStream response = sgc.getFeedAsStream(feedUrl, authToken, null, "2.1");
}
AND
Please have a look at the sample code in the google data api. The important thing to do after authentication is to call GoogleHeaders.setGoogleLogin(String).
I hope this helps.
Ran into a similar issue myself. I found that I need to set the xoauth_requestor_id in the unknown keys list ( reference : http://www.yenlo.nl/2011/google-calendar-api-v3-and-2lo/ )
This worked for me:
com.google.api.services.calendar.Calendar.CalendarList.List list = calendar.calendarList().list();
//Set the requestor id
list.getUnknownKeys().put("xoauth_requestor_id", "user#gmail.com");
After this the API calls went thru.
I wish there was a explanation as to why the requestor id is needed. Can someone explain?
Please, at least pseudo (but from working environment not "maybe this should work") application context and controller/filter that will authenticate and/or auto-register Facebook users.
This link: http://blog.kadirpekel.com/2009/11/09/facebook-connect-integration-with-spring-security/ will not do. Actually I will put minus point to anyone who will post it as answer. I spend 2 hours with the thing and I didn't get it to work. I ended bit more bolder and feeling more stupid than usual after this endeavor :-(
I would really like to see OAuth 2.0 solution for facebook connect. And restrict the use of Facebook JavaScript API to absolute minimum.
Following link shows about what I need:
http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/
Please post only code to this question. I already got all the advice I can handle.
UPDATE
I have servlet solution and posted answer here if anyone is interested:
Facebook Connect example in JSP (tomcat)
Here's an MVC implementation of facebook OAuth 2.0
The code's in C# and hopefully its similarity with java helps you out.
Controller(Entry point):Controller(in MVC) is the point in the code where the control reaches after someone clicks on the login link.
public ActionResult Authenticate()
{
var oauthFacebook = new FacebookOAuth();
if (Request["code"] == null)
{
//Redirect the user to Facebook for authorization.
Response.Redirect(oauthFacebook.AuthorizationLinkGet());
}
else
{
//Get the access token and secret.
oauthFacebook.AccessTokenGet(Request["code"]);
if (oauthFacebook.Token.Length > 0)
{
//We can now make our api calls
var user = oauthFacebook.GetAttributes();
}
}
}
FacebookOAuth Class
public class FacebookOAuth : Oauth
{
public FacebookOAuth()
{
Authorize = "https://graph.facebook.com/oauth/authorize";
AccessToken = "https://graph.facebook.com/oauth/access_token";
CallbackUrl = "http://<YourURLHere>/Authenticate";
AttributesBaseUrl = "https://graph.facebook.com/me/?access_token=";
ConsumerKey = ConfigurationManager.AppSettings["FacebookConsumerKey"];//Ur Consumer Key goes here
ConsumerSecret = ConfigurationManager.AppSettings["FacebookConsumerSecret"];//Ur Consumer secret goes here
Provider = "Facebook";
}
public override string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=email,user_education_history,user_location,user_hometown",
Authorize, ConsumerKey, CallbackUrl);
}
public User GetAttributes()
{
string attributesUrl = string.Format("{0}{1}", AttributesBaseUrl, Token);
string attributes = WebRequest(Method.Get, attributesUrl, String.Empty);
var FacebookUser = new JavaScriptSerializer().Deserialize<FacebookUser>(attributes);
return new User()
{
FirstName = FacebookUser.first_name,
MiddleName = FacebookUser.middle_name,
LastName = FacebookUser.last_name,
Locale = FacebookUser.locale,
UserEmail = FacebookUser.email,
AuthProvider = Provider,
AuthToken=Token
};
}
}
OAuth baseclass(Class from which FacebookOAuth derives)
public abstract class Oauth
{
#region Method enum
public enum Method
{
Get,
Post,
Delete
} ;
#endregion
protected string AccessToken;
protected string AttributesBaseUrl;
protected string Authorize;
protected string CallbackUrl;
protected string ConsumerKey;
protected string ConsumerSecret;
public string Provider { get; protected set; }
public string Token { get; set; }
public virtual string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=publish_stream,email,user_education_history,user_location",
Authorize, ConsumerKey, CallbackUrl);
}
public void AccessTokenGet(string authToken)
{
Token = authToken;
string accessTokenUrl = string.Format("{0}?client_id={1}&redirect_uri={2}&client_secret={3}&code={4}",
AccessToken, ConsumerKey, CallbackUrl, ConsumerSecret, authToken);
string response = WebRequest(Method.Get, accessTokenUrl, String.Empty);
if (response.Length > 0)
{
//Store the returned access_token
NameValueCollection qs = HttpUtility.ParseQueryString(response);
if (qs["access_token"] != null)
{
Token = qs["access_token"];
}
}
}
public string WebRequest(Method method, string url, string postData)
{
StreamWriter requestWriter;
string responseData = string.Empty;
var webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
if (webRequest != null)
{
webRequest.Method = method.ToString();
webRequest.ServicePoint.Expect100Continue = false;
webRequest.Timeout = 20000;
if (method == Method.Post)
{
webRequest.ContentType = "application/x-www-form-urlencoded";
//POST the data.
requestWriter = new StreamWriter(webRequest.GetRequestStream());
try
{
requestWriter.Write(postData);
}
finally
{
requestWriter.Close();
}
}
responseData = WebResponseGet(webRequest);
}
return responseData;
}
public string WebResponseGet(HttpWebRequest webRequest)
{
StreamReader responseReader = null;
string responseData;
try
{
responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
responseData = responseReader.ReadToEnd();
}
finally
{
if (webRequest != null) webRequest.GetResponse().GetResponseStream().Close();
if (responseReader != null) responseReader.Close();
}
return responseData;
}
}
I actually just finished my non-javascript, implementation of the Facebook Graph API Authentication last night. I was a gargantuan pain in the a**, but it works and it's working fairly well.
I used the example from the link you posted above as a starting point, as well as, the code from here as a starting point. I had to write my own implementation of their FacebookGraphAuthenticationProvider and their FacebookGraphAuthenticationFilter, but now it works the way I want it to.
You need to create implementations of both of these files, put your filter in the filter chain, and create a implementation of the Spring Security UserDetailsService that the Provider can use to manage your user account information. I have some code on my machine at home that I can send you via email if you like.
Here are the steps I had to use to get the authentication to work:
Get an "code" for a user, this is done by making the following call: https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream (The scope is all the permissions you want to request from FB). This call will create an "authentication code" which will then be sent back to your "redirect_uri" (which I stated as http://{my fb app registered domain}/j_spring_security_authentication_check.
Once you have this "code", you need to make a call within your AuthenticationProvider that will retrieve an access_token for your user's session: this URL looks like: https://graph.facebook.com/oauth/access_token? client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE. You have to make sure your "redirect_uri" is the same as the one you did in #1. You'll make the above call using something like Apache's HttpClient, or the like.
Now with this access_token (which comes in the body of above response), you can get your user's profile information with the following URL: https://graph.facebook.com/me?access_token={ACCESS_TOKEN from above). The response will be in JSON. You can also use the access_token with all of the graph API to post status, pictures, etc.
I have some code at home that has my full implementation that I would be happy to share.
I hope this helps at least a bit. I suggest using the Spring Social app to get started with posting status, pictures, wall stuff, etc. This will be a good place to start looking at FB-Spring interaction.