I need to obtain OAuth2 authentication token to pass it to the server so it can fetch list of Google Reader feeds for the user. Server is .NET - I have no access to it or to it's code but most likely it is using unofficial Reader API
I was able to use Android Account manager to obtain valid token for this purpose with the following code (notice that authTokenType="reader")
Account account = accounts[0];
manager.getAuthToken(account, "reader", null, this, new AccountManagerCallback<Bundle>() {
public void run(AccountManagerFuture<Bundle> future) {
try {
// If the user has authorized your application to use the tasks API
// a token is available.
String token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
// Now you can send the token to API...
cacheManager.putString(GOOGLE_AUTH, token);
GoogleReaderManager.startAddFeedActivity(AddGoogleReaderSourcesActivity.this);
finish();
} catch (OperationCanceledException e) {
Log.e(TAG, "User cancelled", e);
finish();
} catch (Exception e) {
Log.e(TAG, "Failed to obtain Google reader API_KEY", e);
}
}
}, null);
The code above works fine when I send token to the server side .Net app: the app is able to retrieve the list of Reader feeds.
The problem is that this only works for "Google inside" devices. On Nook I have no such luck since there's no way that I was able to find to add Google account to the account manager. So I'm trying to it using OAuth 2 protocol as described here
It works fine as far as obtaining the token: User approves the app from the mobile page which returns the code token which then mobile app exchanges for the Auth token. However this token will not work with the server process. I have a feeling that perhaps I'm using the wrong scope in this URL:
https://accounts.google.com/o/oauth2/auth?response_type=code&scope=https://www.google.com/reader/api/0/subscription/list&redirect_uri=http://localhost&approval_prompt=force&state=/ok&client_id={apps.client.id}
Scopes that I did try in various combinations:
https://www.google.com/reader/api
https://www.google.com/reader/api/0
https://www.google.com/reader/api/0/subscription/list
https://www.google.com/reader/api+https://www.google.com/reader/atom
Here's example of JSON that is returned from get token POST
{"expires_in":3600,
"token_type":"Bearer",
"access_token":"ya29.AHES6ZSEvuUb6Bvd2DNoMnnN_UnfxirZmf_RQjn7LptFLfI",
"refresh_token":"1\/bUwa5MyOtP6VyWqaIEKgfPh08LNdawJ5Qxz6-qZrHg0"}
Am I messing up scope or token type? Not sure how to change a token type. Any other ideas?
P.S. Google account login page asks: Manage your data in Google Reader, that's why I suspect that the scope is wrong
I got it working for https://www.google.com/reader/api/0/subscription/list. So thought of sharing with you.
I have valid access_token:
This is what i tried to resolve it (partially) :
Google provides OAuth 2.o playgound; where they actually simulate all aspects of OAuth 2.0 as well as final API call to fetch data.
I found this very helpful as it clearly shows what is being sent to request.
Here is the URL : https://developers.google.com/oauthplayground/
Using this, i tweaked my api call below and it works :)
public static String getReaderContent(String accessToken){
String url = "https://www.google.com/reader/api/0/subscription/list" ;
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
String response="";
method.setRequestHeader("Authorization", "OAuth "+accessToken);
try {
int statusCode = client.executeMethod(method);
String response= method.getResponseBodyAsString();
System.out.println("response " + responseStr);
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
So this works properly fine for getting subscription list; but have not been able to make it work for reader api which you have mentioned in your question.
Let me know if you have got way around google reader API.
Related
I'm trying to retrieve a Google user's contacts list.
This getContacts() is called in the doInBackground() of an AsyncTask.
I have -at this point- already received a token.
I based my self on this codeLab sample : https://codelabs.developers.google.com/codelabs/appauth-android-codelab/#0
I'm modifying the point n°10 of this tutorial so trying to fetch user's contact list instead of the user's personal info ( < which is working)
private List<ContactEntry> getContacts() {
ContactsService contactsService = new ContactsService("MY_PRODUCT_NAME");
contactsService.setHeader("Authorization", "Bearer " + token);
try {
URL feedUrl = new URL("https://www.google.com/m8/feeds/contacts/default/full");
Query myQuery = new Query(feedUrl);
ContactFeed resultFeed = contactsService.query(myQuery, ContactFeed.class);
List<ContactEntry> contactEntries = resultFeed.getEntries();
return contactEntries;
} catch (Exception e) {
}
return null;
}
My problem is that I always get an Exception with this message :
java.lang.NullPointerException: No authentication header information
Any help?
thanks in advance
You may refer with this related thead. Try modifying the client library's user
agent:
A workaround is to change the user agent of your client after you create it:
ContactsService service = new ContactsService(applicationName);
service.getRequestFactory().setHeader("User-Agent", applicationName);
Also based from this post, service.setOAuth2Credentials() doesn't refresh token internally like the other services in Google Sites, Google Drive and etc. If you build Google Credential, just add this line after building the Google Credential: googleCredential.refreshToken();.
I'm developing an Android app that consumes data from my own REST API server. I want to use Firebase authentication because it allows the user to login using Google, Facebook, Twitter... in a very simple way.
But I'm not sure how to use ID tokens:
Because ID tokens have expiration date, should I call getToken method on every request in the client app, so I'm sure I'm sending a valid token every time?
Should I call verifyIdToken in the server each time I receive a request from the client app?
I don't know what these methods (getToken and verifyIdToken) do under the hood, and because they are asynchronous, I fear they are doing a request to Firebase servers on every call. So I think that making 2 request to Firebase servers in each of my requests is not the way to go...
Both getToken() and VerifyIdToken() are designed to be called for every outgoing/incoming request.
1) Although getToken() is asynchronous, the Firebase Android SDK actually caches the current Firebase user token in local storage. So long as the cached token is still valid (i.e. within one hour since issued), getToken() returns the token immediately. Only when the cached token expires does the SDK fetch a new token from remote Firebase server.
2) VerifyIdToken() is also optimized for performance. It caches the Firebase token public cert (valid for 6 hours) which is used to validate the token signature on local machine. No RPC is involved except for downloading the public cert.
You refresh token each time when is no more valid. And yes, you should verify token on server-side each time. If is no more valid, you send 401 error code with error message (if you want). Verify token is used when you refresh token, and token is append to each request. If you use OkHttp you can create an interceptor that is adding token in header to each request and also can refresh token when error code is 401.
POST https://YOUR_AUTH0_DOMAIN/delegation
Content-Type: 'application/json'
{
"client_id": "YOUR_CLIENT_ID",
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"refresh_token": "your_refresh_token",
"api_type": "app"
}
From what you have explained in the question, I guess you are talking about cross client resource access using Google sign in. And specifically you seem to be interested in obtaining the Id token once and use it without having to obtain on each subsequent API call.
This more or less is synonymous with the offline access mechanism.
In offline access, the Client I.e. the Android app asks for user authorisation for requested scopes. Upon authorisation, instead of issuing an access token, auth server returns a short lived authorisation code which can be used to generate an access token and refresh token.
The client then can pass the authorisation code to the backend over a secure connection. Backend server can retrieve the author token and refresh token and store them in a secure location. The access token is short lived and can be used to access scoped resources for a short time and refreshed from time to time using the refresh token. The refresh token does not expire but can be revoked. If revoked, server app should ask the client app to re-fetch the author code.
Please go through this link which details the complete infrastructure along with the steps to be followed both by client and server app -
https://developers.google.com/identity/protocols/CrossClientAuth
Now coming to your question, you should use a slightly different API to obtain the auth code. Check out this API -
https://developers.google.com/android/reference/com/google/android/gms/auth/api/signin/GoogleSignInOptions.Builder.html#requestServerAuthCode(java.lang.String)
Sample code at - https://developers.google.com/identity/sign-in/android/offline-access
Use below code in your application class and regId is the value holder for your device token.
private void checkPlayService() {
// Check device for Play Services APK. If check succeeds, proceed with
// GCM registration.
if (checkPlayServices()) {
GoogleCloudMessaging googleCloudMessaging = GoogleCloudMessaging.getInstance(activity);
regId = getRegistrationId();
if (TextUtils.isEmpty(regId)) {
registerInBackground();
}
} else {
Log.i(TAG, "No valid Google Play Services APK found.");
}
}
private String getRegistrationId() {
String registrationId = sp.getString(Consts.PROPERTY_REG_ID, "");
if (TextUtils.isEmpty(registrationId)) {
Log.i(TAG, "Registration not found.");
return "";
}
// Check if app was updated; if so, it must clear the registration ID
// since the existing regID is not guaranteed to work with the new
// app version.
int registeredVersion = sp.getInt(PROPERTY_APP_VERSION,0);
int currentVersion = getAppVersion();
if (registeredVersion != currentVersion) {
Log.i(TAG, "App version changed.");
return "";
}
return registrationId;
}
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (googleCloudMessaging == null) {
googleCloudMessaging = GoogleCloudMessaging.getInstance(activity);
}
regId = googleCloudMessaging.register(Consts.PROJECT_NUMBER);
msg = "Device registered, registration ID=" + regId;
Log.e("GCMID",msg);
storeRegistrationId(regId);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
Log.i(TAG, msg + "\n");
}
}.execute(null, null, null);
}
private void storeRegistrationId(String regId) {
int appVersion = getAppVersion();
Log.i(TAG, "Saving regId on app version " + appVersion);
sp.edit().putString(Consts.PROPERTY_REG_ID, regId).commit();
sp.edit().putInt(PROPERTY_APP_VERSION, appVersion).commit();
}
i'm trying to integrate 'Log in with Google' in app that have an android and web component. Everything in the web component is working fine with the following steps:
1. Rendering the view with an anti-forgery token, client id and app name.
$state = md5(rand());
Session::set('state', $state);
$this->view->render('login', array(
'CLIENT_ID' => 'my_web_client_id',
'STATE' => $state,
'APPLICATION_NAME' => 'my_app_name'));
2. When user clicks on the Google's SignIn button, obtain the one-time code from Google's servers and send it to my server.
3. After my server receives the one-time code using https://github.com/google/google-api-php-client to authenticate the user with that code.
if ($_SESSION['state'] != $_POST['state']) { // Where state is the anti-forgery token
return 'some error';
}
$code = $_POST['code'];
$client = new Google_Client();
$client->setApplicationName("my_app_name");
$client->setClientId('my_web_client_id');
$client->setClientSecret('client_secret');
$client->setRedirectUri('postmessage');
$client->addScope("https://www.googleapis.com/auth/urlshortener");
$client->authenticate($code);
$token = json_decode($client->getAccessToken());
// Verify the token
$reqUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' . $token->access_token;
$req = new Google_Http_Request($reqUrl);
$tokenInfo = json_decode($client->getAuth()->authenticatedRequest($req)->getResponseBody());
// If there was an error in the token info, abort.
if ($tokenInfo->error) {
return 'some error';
}
// Make sure the token we got is for our app.
if ($tokenInfo->audience != "my_web_client_id") {
return 'some error';
}
// Saving user in db
...
// Load the app view
Now, for android client should be something similar, right? Following these tutorials:https://developers.google.com/+/mobile/android/sign-in and http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/
Executing async task in onConnected method
class CreateToken extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
oneTimeCode = getOneTimeCode();
String email = getUserGPlusEmail();
try {
// Opens connection and sends the one-time code and email to the server with 'POST' request
googleLogin(oneTimeCode, email);
} catch (IOException e) {
e.printStackTrace();
}
return oneTimeCode;
}
}
private String getOneTimeCode() {
String scopes = "oauth2:server:client_id:" + SERVER_CLIENT_ID + ":api_scope:" + SCOPE_EMAIL;
String code = null;
try {
code = GoogleAuthUtil.getToken(
LoginActivity.this, // Context context
Plus.AccountApi.getAccountName(mGoogleApiClient), // String accountName
scopes // String scope
);
} catch (IOException transientEx) {
Log.e(Constants.TAG, "IOException");
transientEx.printStackTrace();
// network or server error, the call is expected to succeed if you try again later.
// Don't attempt to call again immediately - the request is likely to
// fail, you'll hit quotas or back-off.
} catch (UserRecoverableAuthException e) {
Log.e(Constants.TAG, "UserRecoverableAuthException");
e.printStackTrace();
// 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);
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
Log.e(Constants.TAG, "GoogleAuthException");
authEx.printStackTrace();
} catch (Exception e) {
throw new RuntimeException(e);
}
Log.e(Constants.TAG, "ONE TIME CODE: " + code);
return code;
}
After obtaining the code successfully, send it to my server for authentication.
And here's the code on the server:
$code = $_POST['code'];
$client = new Google_Client();
$client->setApplicationName("my_app_name");
$client->setClientId('my_web_client_id'); // Web component's client id
$client->setClientSecret('client_secret'); // Web component's secret
$client->addScope("email");
$client->setAccessType("offline");
$client->authenticate($code);
...
And the problem is that authentication works only once every 10-15 minutes. When trying to obtain the one-time code more than once in 10-15 minutes, i get the same code as the last one(Clearly there is something wrong. This happens only with the android client and i'm getting this error: Error fetching OAuth2 access token, message: 'invalid_grant: i'). Couldn't find anyone with the same problem here in SO. Probably i'm doing something wrong, but can't figure out what is it...Any help would be appreciated.
You shouldn't be sending the code each time. On the web this is kind of OK as when you first consent you'll get a code that gives you offline access (you'll see a refresh token in the response when you exchange it) but in future cases you wont. On Android, you get a code that gives you a refresh token every time, which means you'll need to show the consent every time, and you're likely to run into per-user limits or cache issues (as you seem to be).
The magic extra component you need is a thing called an ID token. This you can get easily on both platforms and tells you who the person is. Take a look at this blog post for more: http://www.riskcompletefailure.com/2013/11/client-server-authentication-with-id.html
The limitation with an ID token is that you can't use it to call Google APIs. All it does is give you the Google user ID, the client ID of the app being used and (if email scope is used) the email address. The nice thing is that you can get one really easily on all platforms with less user interaction, and they're cryptographically signed so most of the time you can use them without making any further network calls on the server. If you don't need to make Google API calls (because you're just using it for auth) this is the best thing to use by far - given that you're just getting the email, I would be inclined to stop here.
If you need to make Google API calls from your server though, then you should use the code - but just once. When you exchange it, you store the refresh token in a database keyed against the user ID. Then, when the user comes back you look up the refresh token and use it to generate a new access token. So the flow would be:
First time:
Android -> Server: id token
Server -> I have no refresh token!
Android -> Server: code
Other times:
Android -> Server: id token
Server - I have a code, and can make calls.
For the web, you can use the same flow or carry on sending the code each time, but you should still keep the refresh token in the database if the response contains one.
I want to post score points using facebook graph api, from my android application
I create android app in facebook developers page. I set to Native Android App , and I set Mobile Web settings like on image below
In android code I user this permissions for my app:
String[] permissions = {"publish_stream","publish_actions","user_games_activity","friends_games_activity"};
After successful login on facebook, I try to post score points to facebook using this android code
Bundle params = new Bundle();
params.putString("score", "100");
//params.putString("access_token", "token as constant");
String response = "null";
Utility.mFacebook.setAccessToken("token as constant");
try {
response = Utility.mFacebook.request("user_id/scores", params, "POST");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
And I receive this response:
{"error":{"message":"(#15) This method must be called with an app access_token.","type":"OAuthException","code":15}}
I get same error if I use Graph API Explorer:
In facebook settings ->Apps -> AppName -> Advanced->App Type is set to "Web" (I also try with Native/Desktop but I get same error)
Can anyone help me and tell me how to sent score from my android app to fb?
Thanks
"(#15) This method must be called with an app access_token."
Looks like you tried with an user access token.
See https://developers.facebook.com/docs/authentication/applications/ on how to get an app access token.
I am trying to integrate yahoo in my app. I am trying,
private static final String YAHOO_CALLBACK_URI = "MyApp://oauth";
public static final String YAHOO_REQUEST_TOKEN_URL = "http://api.login.yahoo.com/oauth/request_token";//api.login.yahoo.com
public static final String YAHOO_ACCESS_TOKEN_URL = "http://api.login.yahoo.com/oauth/access_token";
public static final String YAHOO_AUTHORIZE_URL = "http://api.login.yahoo.com/authorize";
CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(YAHOO_CONSUMER_KEY, YAHOO_CONSUMER_SERECT_KEY);
OAuthProvider provider = new CommonsHttpOAuthProvider(YAHOO_REQUEST_TOKEN_URL, YAHOO_ACCESS_TOKEN_URL, YAHOO_AUTHORIZE_URL);
provider.setOAuth10a(true);
try {
String authUrl = provider.retrieveRequestToken(consumer, YAHOO_CALLBACK_URI);// Can I pass Null for callback url.
System.out.println("AuthURL = " + authUrl);
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthNotAuthorizedException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
getting
oauth.signpost.exception.OAuthCommunicationException: Communication with the service provider failed: Service provider responded in error: 404 (Not Found)
Why we are unable to retrieve request token.
Make sure your app on Yahoo is registered as Web-Based. When you register as a Web-Based application, give a valid Application URL and App Domain of your choice (both should be the same domain), but has not been used by anyone else. I, for example, have the url of a website I own. This will also be used as the callback url in your consumer.
Instead of calling "MyApp://oauth", give a valid http callback url (the same one you used to register the app). With that much, your code above should work.
Open a new Webview and call the authUrl. Once your app is authorised, intercept the call to your application url by overriding the "onPageStarted" method. There, make a callback to your app by launching a new intent pointing to "MyApp://oauth".
Please let me know if any of the obove steps confuse you - I am more than happy to help.
I had followed the above mentioned 3#poits and able to do the call back to the application. The whole problem started with YAHOO OAUTH Process. Now Yahoo doesnt take the Custom Call back urls, It has to be a valid http url. n
There are couple of issues i have it which i am solving on my own,like Having a CUSTOMi Dialog box which can be used to call the Web-view YAHOO Auth URL similar to FB Dialog.
Thanks for the