execute youtube playlists got GoogleJsonResponseException: 401 Unauthorized - android

I use android AccountManager to get authToken like this:
private void getGoogleAccountName(){
AccountManager.get(activity.getApplicationContext())
.getAuthTokenByFeatures("com.google", "oauth2:https://gdata.youtube.com", null, activity, null, null, this, null);
}
// I implement AccountManagerCallback<Bundle> in this class
#Override
public void run(AccountManagerFuture<Bundle> future) {
boolean hasAccount = checkGoogleAccount(future);
if (hasAccount) {
getYoutubeVideoByLib("");
}
}
private boolean checkGoogleAccount(AccountManagerFuture<Bundle> future){
try {
Bundle bundle = future.getResult();
accountName = bundle.getString(AccountManager.KEY_ACCOUNT_NAME);
authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
} catch (Exception e) {
return false;
}
return true;
}
then I use google apis with authToken trying to get user's playlists
private void getYoutubeVideoByLib(String pageToken){
YouTube youtube = new YouTube.Builder(
new NetHttpTransport(),
new JacksonFactory(),
new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request) throws IOException {
}
}).setApplicationName(activity.getString(R.string.app_name)).build();
YouTube.Playlists.List query = null;
try{
query = youtube.playlists().list("snippet");
query.setOauthToken(authToken);
query.setKey("YOUTBE_API_KEY");
query.setMine(true);
if(!TextUtils.isEmpty(pageToken)) {
query.setPageToken(pageToken);
}
PlaylistListResponse response = query.execute();
...
} catch(IOException e) {
return;
}
}
but I found out some google account got GoogleJsonResponseException in query.execute();
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"
}
the weird thing is that, some accounts work fine before but after these users got this exception, they can't get their playlists anymore.
Does anyone meet the same problem?
===================================================================
I solved it myself. I made a big mistake...
In google developer console, I set API KEY but not OAuth 2.0 client ID.
After setting both and change code below, it work fine now.
String[] SCOPES = {YouTubeScopes.YOUTUBE_READONLY};
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(getApplicationContext(), Arrays.asList(SCOPES));
credential.setSelectedAccountName(accountName);
YouTube youtube = new YouTube.Builder(transport, jsonFactory, credential).setApplicationName(getString(R.string.app_name)).build();

Related

Unable to get linkden access token in Android (access toke is not set)

Unable to get access token, is given an exception "access token is not set"
On onAuthSuccess, it return me response {"expiresOn": 0}
It was working fine 1 month ago, suddenly it stops to work in all Android apps
final LISessionManager sessionManager = LISessionManager.getInstance(getApplicationContext());
sessionManager.init(MainActivityVC.this, buildScope(), new AuthListener() {
#Override
public void onAuthSuccess() {
Log.e("Access Token", "== "+sessionManager.getSession().getAccessToken());
//output -> Access Token = {"expiresOn": 0}
Log.e("is Token Valid", "== "+sessionManager.getSession().isValid());
//output -> is Token Valid = false
}
#Override
public void onAuthError(LIAuthError error) {
// Handle authentication errors
}
}, true);
private static Scope buildScope() {
return Scope.build(Scope.R_BASICPROFILE, Scope.R_EMAILADDRESS);
}

YouTube Data API v3 Authentification Error

I'm trying to access the YouTube Data API v3 from within my app to fetch some videos from a specific channnel. I created an API Key and inserted my package name and the SHA-1 fingerprint. However, it does not work.
This is the error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "usageLimits",
"message" : "The Android package name and signing-certificate fingerprint, null and null, do not match the app restrictions configured on your API key. Please use the API Console to update your key restrictions.",
"reason" : "ipRefererBlocked",
"extendedHelp" : "https://console.developers.google.com/apis/credentials?project=1097633804344"
} ],
"message" : "The Android package name and signing-certificate fingerprint, null and null, do not match the app restrictions configured on your API key. Please use the API Console to update your key restrictions."
}
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at de.axelrindle.youtubeapitest.YoutubeConnector.fetchVideoIDS(YoutubeConnector.java:59)
at de.axelrindle.youtubeapitest.util.VideoIDFetcher.fetchVideoIDS(VideoIDFetcher.java:62)
at de.axelrindle.youtubeapitest.InitService.onHandleIntent(InitService.java:57)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
And here is the code, which sends the request:
YoutubeConnector.class
public YoutubeConnector(Context context) {
this.context = context;
youTube = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request) throws IOException {}
}).setApplicationName("YouTube Data API v3 Test").build();
try {
query = youTube.search().list("id,snippet");
query.setKey(DevKey.YOUTUBE_API);
query.setType("video");
query.setFields("items(id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url)");
query.setChannelId("UC3ifTl5zKiCAhHIBQYcaTeg");
query.setMaxResults(maxResults);
} catch (IOException e) {
Log.e("YoutubeConnector", "Failed to connect to YouTube: " + e.getMessage());
}
}
public List<String> fetchVideoIDS() {
List<String> ids = new ArrayList<>();
maxResults += 10;
try {
SearchListResponse response = query.execute();
List<SearchResult> results = response.getItems();
for (SearchResult result : results) {
ids.add(result.getId().getVideoId());
}
} catch (IOException e) {
e.printStackTrace();
}
return ids;
}
Any help is MUCH appreciated!
Fixed it by myself.
I was just using the wrong API key.
EDIT:
Maybe I should mention that it worked when I used an browser api key instead of an android api key.

Android - AccountManager Twitter OAuth, no authentication challenges found

I am trying to get OAuth token from AccountManager for twitter account and using it to follow a twitter handle using Twitter4j. But I am getting no authenticating challenges found TwitterException.
Bellow is the code to get the token and follow the user:
try{
AccountManager accountManager = AccountManager.get(getActivity());
Account twitterAccount = accountManager.getAccountsByType(AccountType.TWITTER.getType())[0];
AccountManagerFuture<Bundle> tokenFuture = accountManager.getAuthToken(twitterAccount, "com.twitter.android.oauth.token", null, true, new AccountManagerCallback<Bundle>() {
public void run(AccountManagerFuture<Bundle> result) {
Bundle bundle;
try {
bundle = result.getResult();
Intent intent = (Intent) bundle.get(AccountManager.KEY_INTENT);
if (intent != null) {
// User input required
getActivity().startActivity(intent);
} else {
String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
Log.i(TAG, "Token:" + token);
userToken = token;
}
} catch (Exception e) {
Log.e(TAG, "Error getting token", e);
}
}
}, null);
AccountManagerFuture<Bundle> secretFuture = accountManager.getAuthToken(twitterAccount, "com.twitter.android.oauth.token.secret", null, true, new AccountManagerCallback<Bundle>() {
public void run(AccountManagerFuture<Bundle> result) {
Bundle bundle;
try {
bundle = result.getResult();
Intent intent = (Intent) bundle.get(AccountManager.KEY_INTENT);
if (intent != null) {
// User input required
getActivity().startActivity(intent);
} else {
String secret = bundle.getString(AccountManager.KEY_AUTHTOKEN);
Log.i(TAG, "Secret Token:" + secret);
userSecret = secret;
}
} catch (Exception e) {
Log.e(TAG, "Error getting token", e);
}
}
}, null);
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder
.setOAuthConsumerKey(<Consumer-key>);
configurationBuilder
.setOAuthConsumerSecret(<Consumer-Secret>);
configurationBuilder.setOAuthAccessToken(userToken);
configurationBuilder.setOAuthAccessTokenSecret(userSecret);
Twitter twitter = new TwitterFactory(configurationBuilder.build()).getInstance();
User user = twitter.createFriendship(param.getUserName());
Toast.makeText(followListActivity,"Followed user #"+user.getScreenName()+" :)",Toast.LENGTH_SHORT);
} catch (TwitterException e) {
e.printStackTrace();
}
Getting this exception:
TwitterException{exceptionCode=[ec1fe56d-1e3b4ac5 3ea58453-a92e09a2], statusCode=-1, message=null, code=-1, retryAfter=-1, rateLimitStatus=null, version=4.0.2}
at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:178)
at twitter4j.HttpClientBase.request(HttpClientBase.java:53)
at twitter4j.HttpClientBase.get(HttpClientBase.java:71)
at twitter4j.TwitterBaseImpl.fillInIDAndScreenName(TwitterBaseImpl.java:128)
at twitter4j.TwitterImpl.verifyCredentials(TwitterImpl.java:545)
at asynctask.FollowTwitterUserAsyncTask.doInBackground(FollowTwitterUserAsyncTask.java:113)
at asynctask.FollowTwitterUserAsyncTask.doInBackground(FollowTwitterUserAsyncTask.java:33)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.io.IOException: No authentication challenges found
at libcore.net.http.HttpURLConnectionImpl.getAuthorizationCredentials(HttpURLConnectionImpl.java:438)
at libcore.net.http.HttpURLConnectionImpl.processAuthHeader(HttpURLConnectionImpl.java:418)
at libcore.net.http.HttpURLConnectionImpl.processResponseHeaders(HttpURLConnectionImpl.java:367)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:301)
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
at twitter4j.HttpResponseImpl.<init>(HttpResponseImpl.java:35)
at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:142)
Please point out what I am doing wrong here.
You don’t do anything wrong at all, that’s an issue with the library. In Android, a HTTP response code of 401 causes an IOException be thrown. The library implementor checks for the message string of the IOException to catch it, however your message string is slightly different so the exception handling doesn’t execute. Unluckily, the issue tracker is not enabled for that GitHub project, but you may try to contact the project owner, maybe he will fix it for you. Otherwise you will have to modify the library code and build it yourself.

Google drive SDK 2.0 throws error 400 Bad Request

I've been fighting with Google Drive API for Android for more than 50 hours now, and have not come one inch closer. From my understanding, there are 1001 ways to access Google drive (Google Docs API, REST & Google Drive SDK v2). I'm using Google Drive SDK v2. I want want to access Google Drive to upload jpeg files. Platform, Android 2.2+.
What I've tried:
Using the recently released SDK:
http://code.google.com/p/google-api-java-client/wiki/APIs#Drive_API
I've watched the Google I/O sesssion, but the most important part (how to create a Drive object using your Client ID & Client Secret) was left out:
https://developers.google.com/events/io/sessions/gooio2012/705/
I have created multiple keys on https://code.google.com/apis/console. The last one I've created (and tested with) was created using "Create another client ID..." -> "Installed Application" -> "Android". I've used the key in the ~/.android/debug.keystore.
I've also tried to create a key for an "Other" (instead of Android/iOS) installed app, but this gives me a Client ID and Client secret. It seems like the Drive object does not accept a client secret.
Where the code says "1234567890-abcdefghij123klmnop.apps.googleusercontent.com", I've tried to use both "API key" and the "Client ID", both gave the same error.
My code:
Account account = AccountManager.get(context).getAccountsByType(
"com.google")[0];
String token;
try {
token = GoogleAuthUtil.getToken(context, account.name, "oauth2:"
+ DriveScopes.DRIVE_FILE);
} catch (UserRecoverableAuthException e) {
context.startActivityForResult(e.getIntent(), ASK_PERMISSION);
return;
} catch (IOException e) {
return;
} catch (GoogleAuthException e) {
return;
}
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
Drive.Builder b = new Drive.Builder(httpTransport, jsonFactory, null);
final String tokenCopy = token;
b.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
public void initialize(JsonHttpRequest request) throws IOException {
DriveRequest driveRequest = (DriveRequest) request;
driveRequest.setPrettyPrint(true);
driveRequest
.setKey("1234567890-abcdefghij123klmnop.apps.googleusercontent.com");
driveRequest.setOauthToken(tokenCopy);
}
});
final Drive drive = b.build();
FileList files;
try {
files = drive.files().list().setQ("mimeType=text/plain").execute();
} catch (IOException e) {
e.printStackTrace(); // throws HTTP 400
}
The error I'm getting is:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"location" : "q",
"locationType" : "parameter",
"message" : "Invalid Value",
"reason" : "invalid"
} ],
"message" : "Invalid Value"
}
As the error message suggests, your error is in the query parameter q. The correct syntax for your q parameter is
files = drive.files().list().setQ("mimeType='text/plain'").execute();
and not :
files = drive.files().list().setQ("mimeType=text/plain").execute();
Looking at your code, you are fully authenticated and your request is failing because of this syntax error.

Google Calendar API OAuth2 Troubles on Android Honeycomb

I am working on an Android Honeycomb (v3.0) application that has a requirement of communicating with the Google Calendar API. I would like to allow my application to access a particular Google account's Calendar data in order to read and create events.
Unfortunately, I ran into a problem with authorization using OAuth2. Here's what I have so far:
1) The Google account whose calendar I would like to access is registered within the Android device I am working with.
2) I enabled the Calendar API within the Google APIs Console on the account.
3) I am able to access this account using the following code:
AccountManager accountManager = AccountManager.get(this.getBaseContext());
Account[] accounts = accountManager.getAccountsByType("com.google");
Account acc = accounts[0]; // The device only has one account on it
4) I would now like to obtain an AuthToken for use when communicating with the calendar. I followed this tutorial, but converted everything to work with Google Calendar instead of Google Tasks. I successfully retrieve an authToken from the AccountManager with the account I would like to use by using getAuthToken with AUTH_TOKEN_TYPE == "oauth2:https://www.googleapis.com/auth/calendar".
5) Here's where the problems begin. I am now at this point:
AccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(tokens[0]); // this is the correct token
HttpTransport transport = AndroidHttp.newCompatibleTransport();
Calendar service = Calendar.builder(transport, new JacksonFactory())
.setApplicationName("My Application's Name")
.setHttpRequestInitializer(accessProtectedResource)
.build();
service.setKey("myCalendarSimpleAPIAccessKey"); // This is deprecated???
Events events = service.events().list("primary").execute(); // Causes an exception!
6) Here's the exception returned by the last line:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "usageLimits",
"message" : "Daily Limit Exceeded. Please sign up",
"reason" : "dailyLimitExceededUnreg",
"extendedHelp" : "https://code.google.com/apis/console"
} ],
"message" : "Daily Limit Exceeded. Please sign up"
}
7) According to this Google API Video (wait a minute or so to get to the applicable content), a reason for this exception may be the fact that I did not enable the API access within the Google APIs Console for the account. However, if you look at 2), you can see that I did do so.
8) To me, it seems that the problem is that I was unable to set the Simple API Access Key correctly, because the Calendar.setKey method is deprecated. Within the Google Tasks tutorial that I previously linked, the key is set using Tasks.accessKey = "key". I'm not sure how to get this working with the Calendar API, though. I have tried multiple Google accounts, which all came up with the exception from 5).
9) I would like to point out that the traditional method of using OAuth2 did work for me. Here's the code I used for that:
HttpTransport TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();
String SCOPE = "https://www.googleapis.com/auth/calendar";
String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";
String CLIENT_ID = "myClientID";
String CLIENT_SECRET = "myClientSecret";
String authorizeUrl = new GoogleAuthorizationRequestUrl(CLIENT_ID, CALLBACK_URL, SCOPE).build();
String authorizationCode = "???"; // At this point, I have to manually go to the authorizeUrl and grab the authorization code from there to paste it in here while in debug mode
GoogleAuthorizationCodeGrant authRequest = new GoogleAuthorizationCodeGrant(TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authorizationCode, CALLBACK_URL);
authRequest.useBasicAuthorization = false;
AccessTokenResponse authResponse = authRequest.execute();
String accessToken = authResponse.accessToken; // gets the correct token
GoogleAccessProtectedResource access = new GoogleAccessProtectedResource(accessToken, TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authResponse.refreshToken);
HttpRequestFactory rf = TRANSPORT.createRequestFactory(access);
AccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(accessToken);
HttpTransport transport = AndroidHttp.newCompatibleTransport();
Calendar service = Calendar.builder(transport, new JacksonFactory())
.setApplicationName("My Application's Name")
.setHttpRequestInitializer(accessProtectedResource)
.build();
Events events = service.events().list("primary").execute(); // this works!
10) Finally, my question: I would like to use the account from the AccountManager on the device itself in order to retrieve a working OAuth2 token for use with the Google Calendar API. The second method is not useful for me, because the user will have to manually go to their web browser and get the authorization code, which is not user friendly. Anyone have any ideas? Apologies for the long post, and thanks!
Try adding a JsonHttpRequestInitializer to the builder and setting your key there:
Calendar service = Calendar.builder(transport, new JacksonFactory())
.setApplicationName("My Application's Name")
.setHttpRequestInitializer(accessProtectedResource)
.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
public void initialize(JsonHttpRequest request) {
CalendarRequest calRequest = (CalendarRequest) request;
calRequest.setKey("myCalendarSimpleAPIAccessKey");
}
}).build();
To answer no 10 : I've basically had to do what you had to do working with the TaskSample and then use the Android GData Calendar Sample available here : http://code.google.com/p/google-api-java-client/source/browse/calendar-android-sample/src/main/java/com/google/api/client/sample/calendar/android/CalendarSample.java?repo=samples
to get the AuthToken from the AccountManager itself:
accountManager = new GoogleAccountManager(this);
settings = this.getSharedPreferences(PREF, 0);
gotAccount();
private void gotAccount() {
Account account = accountManager.getAccountByName(accountName);
if (account != null) {
if (settings.getString(PREF_AUTH_TOKEN, null) == null) {
accountManager.manager.getAuthToken(account, AUTH_TOKEN_TYPE,
true, new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle bundle = future.getResult();
if (bundle
.containsKey(AccountManager.KEY_INTENT)) {
Intent intent = bundle
.getParcelable(AccountManager.KEY_INTENT);
int flags = intent.getFlags();
flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
intent.setFlags(flags);
startActivityForResult(intent,
REQUEST_AUTHENTICATE);
} else if (bundle
.containsKey(AccountManager.KEY_AUTHTOKEN)) {
setAuthToken(bundle
.getString(AccountManager.KEY_AUTHTOKEN));
// executeRefreshCalendars();
}
} catch (Exception e) {
handleException(e);
}
}
}, null);
} else {
// executeRefreshCalendars();
}
return;
}
chooseAccount();
}
private void chooseAccount() {
accountManager.manager.getAuthTokenByFeatures(
GoogleAccountManager.ACCOUNT_TYPE, AUTH_TOKEN_TYPE, null,
ExportClockOption.this, null, null,
new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
Bundle bundle;
try {
bundle = future.getResult();
setAccountName(bundle
.getString(AccountManager.KEY_ACCOUNT_NAME));
setAuthToken(bundle
.getString(AccountManager.KEY_AUTHTOKEN));
// executeRefreshCalendars();
} catch (OperationCanceledException e) {
// user canceled
} catch (AuthenticatorException e) {
handleException(e);
} catch (IOException e) {
handleException(e);
}
}
}, null);
}
void setAuthToken(String authToken) {
SharedPreferences.Editor editor = settings.edit();
editor.putString(PREF_AUTH_TOKEN, authToken);
editor.commit();
createCalendarService(authToken);
try {
Events events = service.events().list("primary").execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void createCalendarService(String authToken) {
accessProtectedResource = new GoogleAccessProtectedResource(authToken);
Log.i(TAG, "accessProtectedResource.getAccessToken() = "
+ accessProtectedResource.getAccessToken());
JacksonFactory jsonFactory = new JacksonFactory();
service = com.google.api.services.calendar.Calendar
.builder(transport, jsonFactory)
.setApplicationName("Time Journal")
.setJsonHttpRequestInitializer(
new JsonHttpRequestInitializer() {
#Override
public void initialize(JsonHttpRequest request) {
CalendarRequest calendarRequest = (CalendarRequest) request;
calendarRequest
.setKey("<YOUR SIMPLE API KEY>");
}
}).setHttpRequestInitializer(accessProtectedResource)
.build();
}

Categories

Resources