I'm using the oauth2-essentials library because it was one of the recommended oauth libraries on the uber developers site, and it has been recently updated.
My code looks like this:
executor = new HttpUrlConnectionExecutor();
OAuth2AuthorizationProvider provider = new BasicOAuth2AuthorizationProvider(
URI.create("https://login.uber.com/oauth/v2/authorize"),
URI.create("https://login.uber.com/oauth/v2/token"),
new Duration(1,0,3600) /* default expiration time in case the server doesn't return any */);
OAuth2ClientCredentials credentials = new BasicOAuth2ClientCredentials(
getString(R.string.uberClientId), getString(R.string.uberSecret));
uberOAuthClient = new BasicOAuth2Client(
provider,
credentials,
new LazyUri(new Precoded("my redirect url")) /* Redirect URL */);
generateUberOAuthToken("my phone number", "my password");
}
public void generateUberOAuthToken(final String uName, final String password){
new Thread() {
public void run() {
try {
uberOAuthToken = new ResourceOwnerPasswordGrant(
uberOAuthClient, new BasicScope("profile"), uName, password).accessToken(executor);
}
catch (Exception e){
e.printStackTrace();
}
}
}.start();
}
The exception: org.dmfs.httpessentials.exceptions.UnauthorizedException: Authentication at 'https://login.uber.com/oauth/v2/token' failed. is always thrown. I've tried removing the redirect url so it should use the default from my dashboard, and I've tried added 1 and/or dashes to the phone number. The exception is always thrown when I request an access token. I know my account is setup correctly because this works fine in iOS. I feel like I must be missing something obvious. Anyone else run into this issue?
The token api did not recognize my phone number as a valid login parameter. It worked when I used my email instead.
Related
I am working with authenticating via Google+ according to the following:
https://developers.google.com/+/mobile/android/sign-in
Most of this process seems fine. The problem I'm having is that we need to get a "one-time authorization code" so that our backend servers can perform certain requests on behalf of the user, with their permission. This is covered in the section "Enable server-side api access for your app". However, for a number of reasons, our servers can cause the login to fail, even if the authorization code is valid (e.g. the user doesn't have an account corresponding to the google+ account on our servers yet, in which case they can make one).
If this happens, we might need them to login again at a later time. What I'm finding, though, is that when I perform the second login with google+, it gives me the same authorization code, even if it's already been used by our servers. I've tried disconnecting and reconnecting to the google client api, and calling GoogleApiClient.clearDefaultAccountAndReconnect(), but no matter what I do, I seem to end up with the same authorization code. This, of course, is rejected by the server when it tries to use it, since it's already been used.
I'm wondering what I'm doing wrong here. I have the following method, which is called during the initial authentication process, and then again if a response status of 500 is detected from our server (indicating the previous call failed, presumably because the code has already been used):
private void dispatchGooglePlusAuthCodeAcquisition() {
AsyncTask<Void, Void, String> authAcquisition = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
Bundle authPreferences = new Bundle();
mUserPermissionNeededForAuthCode = false;
authPreferences.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
"");
String scopesString = Scopes.PROFILE;
WhenIWorkApplication app = (WhenIWorkApplication)WhenIWorkApplication.getInstance();
String serverClientID = app.getGoogleOAuthClientIDForPersonalServer();
String scope = "oauth2:server:client_id:" + serverClientID + ":api_scope:" + scopesString;
String code = null;
authPreferences.putBoolean(GoogleAuthUtil.KEY_SUPPRESS_PROGRESS_SCREEN, true);
try {
code = GoogleAuthUtil.getToken(
mActivity,
Plus.AccountApi.getAccountName(mGoogleApiClient),
scope,
authPreferences
);
} catch (IOException transientEx) {
// 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.
Log.d(LOGTAG, "Encountered an IOException while trying to login to Google+."
+ " We'll need to try again at a later time.");
} catch (UserRecoverableAuthException e) {
mUserPermissionNeededForAuthCode = true;
// 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.
if (!mGooglePlusPermissionActivityStarted) {
mGooglePlusPermissionActivityStarted = true;
mActivity.startActivityForResult(e.getIntent(), RESULT_CODE_AUTH_CODE);
}
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
Log.e(LOGTAG, "Unable to authenticate to Google+. Call will likely never"
+ " succeed, so bailing.", authEx);
}
return code;
}
#Override
protected void onPostExecute(String aResult) {
if (aResult != null) {
// We retrieved an authorization code successfully.
if (mAPIAccessListener != null) {
mAPIAccessListener.onAuthorizationCodeGranted(aResult);
}
} else if (!mUserPermissionNeededForAuthCode) {
// If this is the case, then we didn't get authorization from the user, or something
// else happened.
if (mAPIAccessListener != null) {
mAPIAccessListener.onAuthorizationFailed();
}
Log.d(LOGTAG, "Unable to login because authorization code retrieved was null");
}
}
};
authAcquisition.execute();
So, the answer to this was a lot simpler than I imagined. Apparently, there is aclearToken() method on the GoogleAuthUtil class:
http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html#clearToken%28android.content.Context,%20java.lang.String%29
public static void clearToken (Context context, String token)
Clear the specified token in local cache with respect to the Context. Note that the context must be the same as that used to initialize the token in a previous call to getToken(Context, String, String) or getToken(Context, String, String, Bundle).
Parameters
context Context of the token.
token The token to clear.
Throws
GooglePlayServicesAvailabilityException
GoogleAuthException
IOException
Calling this method before attempting to re-authenticate causes Google to generate a new one-time authorization token.
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 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.
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
i developed one app integrated with linkedIn..!
i do SignIn authentication in linkedIn using OAuth Service to post the Network Update..but now how to sign out (de-authenticate) to the LinkedIn automatically?
Thanks in adv..
As per the official blog
Token Invalidation
Now you can invalidate an OAuth token for your application. Just send an OAuth signed GET request to:
https://api.linkedin.com/uas/oauth/invalidateToken
A 200 response indicates that the token was successfully invalidated.
However as per this :
Third party applications do not have any way to log a user out from
LinkedIn - this is controlled by the website. Invalidating the token
makes the user re-authorize the next time they try to use the
application, but once they have logged into LinkedIn their browser
will remain logged in until they log out via the website.
So In conclusion : as of this date of writing, Linked In does not give this support to 3rd Party Applications
Reading your question i have also tried to find solution and also talked to Mr. Nabeel Siddiqui - Author of linkedin-j API
and this was his reply when i asked if it's possible to sign out using linkedin-j api?
Hi Mayur
There is a method LinkedInOAuthService#invalidateAccessToken that is supposed to invalidate your access token. Its not used much by the community so I am not sure if it works as expected or not. Do try it and let me know if there are problems.
Regards
Nabeel Mukhtar
so in my activity i tried it using this way.
final LinkedInOAuthService oAuthService = LinkedInOAuthServiceFactory.getInstance().createLinkedInOAuthService(consumerKey, consumerSecret);
final LinkedInApiClientFactory factory = LinkedInApiClientFactory.newInstance(consumerKey, consumerSecret);
LinkedInRequestToken liToken;
LinkedInApiClient client;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
liToken = oAuthService.getOAuthRequestToken(CALLBACKURL);
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(liToken.getAuthorizationUrl()));
startActivity(i);
}
#Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
Uri uri = intent.getData();
if (uri != null && uri.toString().startsWith(CALLBACKURL))
{
String verifier = intent.getData().getQueryParameter("oauth_verifier");
LinkedInAccessToken accessToken = oAuthService.getOAuthAccessToken(liToken, verifier);
client = factory.createLinkedInApiClient(accessToken);
Connections con = client.getConnectionsForCurrentUser();
//AFTER FETCHING THE DATA I HAVE DONE
oAuthService.invalidateAccessToken(accessToken);
//this is for sign out
}
}
Please, Try this way once and tell me if it solves your problem.
cause I have also donwloaded and seen the SourceCode for linkedin-j API and in
LinkedInOAuthServiceImpl.java
they have given the function and that function also works if we write the same code in our file.
that is,
#Override
public void invalidateAccessToken(LinkedInAccessToken accessToken) {
if (accessToken == null) {
throw new IllegalArgumentException("access token cannot be null.");
}
try {
URL url = new URL(LinkedInApiUrls.LINKED_IN_OAUTH_INVALIDATE_TOKEN_URL);
HttpURLConnection request = (HttpURLConnection) url.openConnection();
final OAuthConsumer consumer = getOAuthConsumer();
consumer.setTokenWithSecret(accessToken.getToken(), accessToken.getTokenSecret());
consumer.sign(request);
request.connect();
if (request.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new LinkedInOAuthServiceException(convertStreamToString(request.getErrorStream()));
}
} catch (Exception e) {
throw new LinkedInOAuthServiceException(e);
}
}