Gmail forwards WebHook URL - api

I am a Java developer, how can I automatically forward the unread emails received by my personal gmail mailbox to the specified webhook URL.I tried to do this in Java but couldn't get it to work.
E.g:
public class GmailQuickstart {
/** Application name. */
private static final String APPLICATION_NAME = "Gmail API Java Quickstart";
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
/** Directory to store authorization tokens for this application. */
private static final String TOKENS_DIRECTORY_PATH = "tokens";
/**
* Global instance of the scopes required by this quickstart.
* If modifying these scopes, delete your previously saved tokens/ folder.
*/
private static final List<String> SCOPES = Collections.singletonList(GmailScopes.GMAIL_LABELS);
private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
/**
* Creates an authorized Credential object.
* #param HTTP_TRANSPORT The network HTTP Transport.
* #return An authorized Credential object.
* #throws IOException If the credentials.json file cannot be found.
*/
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
// Load client secrets.
InputStream in = GmailQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
if (in == null) {
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
}
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline")
.build();
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
//returns an authorized Credential object.
return credential;
}
public static void main(String... args) throws IOException, GeneralSecurityException {
// Build a new authorized API client service.
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Gmail service = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
.setApplicationName(APPLICATION_NAME)
.build();
// Print the labels in the user's account.
String user = "me";
ListLabelsResponse listResponse = service.users().labels().list(user).execute();
List<Label> labels = listResponse.getLabels();
if (labels.isEmpty()) {
System.out.println("No labels found.");
} else {
System.out.println("Labels:");
for (Label label : labels) {
System.out.printf("- %s\n", label.getName());
}
}
}
}
This is the official example I use. The result is a failure.
failure picture

Related

google sign on web application but in authentication it is giving SSL exception error

I am developing google sign in on my web application. I have send ID token on my server and then I want to verify the integrity of token but in authentication it is giving SSL exception error in GoogleIdTokenVerifier.How can I solve it ?
public class VerifyController {
public static final String CLIENT_ID = "";
private static final String APPLICATION_NAME = "";
public static GoogleIdTokenVerifier verifier ;
public static GoogleIdToken token;
private static NetHttpTransport transport;
private static JsonFactory mJFactory;
public Result validate(#PathParam("id") String idtoken) {
try{
// TODO Auto-generated method stub
System.out.println("IN validate");
System.out.println(idtoken);
transport = new NetHttpTransport();
mJFactory = new GsonFactory();
verifier = new GoogleIdTokenVerifier.Builder(transport, mJFactory)
.setAudience(Arrays.asList(CLIENT_ID))
.build();
token = GoogleIdToken.parse(mJFactory, idtoken);
GoogleIdToken token = GoogleIdToken.parse(mJFactory, idtoken);
if (verifier.verify(token)) {
Payload payload = token.getPayload();
System.out.println(payload);
if (payload.getHostedDomain().equals(APPLICATION_NAME)
// If multiple clients access the backend server:
{
System.out.println("User ID: " + payload.getSubject());
} else {
System.out.println("Invalid Domain.");
}
} else {
System.out.println("null ID token.");
}
return null;
}catch(Exception e) {
e.printStackTrace();
}
return null;
}
}
You need to setIssuer while creating object of GoogleIdTokenVerifier
verifier = new GoogleIdTokenVerifier.Builder(transport, mJFactory)
.setAudience(Arrays.asList(CLIENT_ID))
.build(); //instead of this use below code
verifier = new GoogleIdTokenVerifier.Builder(transport, mJFactory)
.setAudience(Arrays.asList(CLIENT_ID))
.setIssuer("accounts.google.com")
.build();

Getting new token on retry before retrying old request with Volley

I have a simple authentication system implemented using Volley. It goes like this:
Get a token from server on login -> an hour later, this token expires -> when it expires, we will find that out on a failed API call, so we should (on retry) -> fetch a new token when that call fails and then -> retry the original call.
I've implemented this, and the token is returning successfully, but because I think I'm doing something wrong with the Volley RequestQueue, the original request uses all it's retrys before the new and valid token is able to be used. Please see the following code:
public class GeneralAPICall extends Request<JSONObject> {
public static String LOG_TAG = GeneralAPICall.class.getSimpleName();
SessionManager sessionManager; //instance of sessionManager needed to get user's credentials
private Response.Listener<JSONObject> listener; //the response listener used to deliver the response
private Map<String, String> headers = new HashMap<>(); //the headers used to authenticate
private Map<String, String> params; //the params to pass with API call, can be null
public GeneralAPICall(int method, String url, Map<String, String> params, Context context, Response.Listener<JSONObject> responseListener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
sessionManager = new SessionManager(context); //instantiate
HashMap<String, String> credentials = sessionManager.getUserDetails(); //get the user's credentials for authentication
this.listener = responseListener;
this.params = params;
//encode the user's username and token
String loginEncoded = new String(Base64.encode((credentials.get(Constants.SessionManagerConstants.KEY_USERNAME)
+ Constants.APIConstants.Characters.CHAR_COLON
+ credentials.get(Constants.SessionManagerConstants.KEY_TOKEN)).getBytes(), Base64.NO_WRAP));
Log.v(LOG_TAG, loginEncoded); //TODO: remove
this.headers.put(Constants.APIConstants.BasicAuth.AUTHORIZATION, Constants.APIConstants.BasicAuth.BASIC + loginEncoded); //set the encoded information as the header
setRetryPolicy(new TokenRetryPolicy(context)); //**THE RETRY POLICY**
}
The retry policy I set is defined as default, but I implement my own retry method as such:
#Override
public void retry(VolleyError error) throws VolleyError {
Log.v(LOG_TAG, "Initiating a retry");
mCurrentRetryCount++; //increment our retry count
mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
if (error instanceof AuthFailureError) { //we got a 401, and need a new token
Log.v(LOG_TAG, "AuthFailureError found!");
VolleyUser.refreshTokenTask(context, this); //**GET A NEW TOKEN**
}
if (!hasAttemptRemaining()) {
Log.v(LOG_TAG, "No attempt remaining, ERROR");
throw error;
}
}
The refresh token task defines a RefreshAPICall
public static void refreshTokenTask(Context context, IRefreshTokenReturn listener) {
Log.v(LOG_TAG, "refresh token task called");
final IRefreshTokenReturn callBack = listener;
RefreshAPICall request = new RefreshAPICall(Request.Method.GET, Constants.APIConstants.URL.GET_TOKEN_URL, context, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
String token = response.getString(Constants.APIConstants.Returns.RETURN_TOKEN);
Log.v(LOG_TAG, "Token from return is: " + token);
callBack.onTokenRefreshComplete(token);
} catch (JSONException e) {
callBack.onTokenRefreshComplete(null); //TODO: log this
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.v(LOG_TAG, "Error with RETRY : " + error.toString());
}
});
VolleySingleton.getInstance(context).addToRequestQueue(request);
}
Our RefreshAPICall definition:
public RefreshAPICall(int method, String url, Context context, Response.Listener<JSONObject> responseListener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
sessionManager = new SessionManager(context); //instantiate
HashMap<String, String> credentials = sessionManager.getRefreshUserDetails(); //get the user's credentials for authentication
this.listener = responseListener;
//encode the user's username and token
String loginEncoded = new String(Base64.encode((credentials.get(Constants.SessionManagerConstants.KEY_USERNAME)
+ Constants.APIConstants.Characters.CHAR_COLON
+ credentials.get(Constants.SessionManagerConstants.KEY_PASSWORD)).getBytes(), Base64.NO_WRAP));
this.headers.put(Constants.APIConstants.BasicAuth.AUTHORIZATION, Constants.APIConstants.BasicAuth.BASIC + loginEncoded); //set the encoded information as the header
setTag(Constants.VolleyConstants.RETRY_TAG); //mark the retry calls with a tag so we can delete any others once we get a new token
setPriority(Priority.IMMEDIATE); //set priority as immediate because this needs to be done before anything else
//debug lines
Log.v(LOG_TAG, "RefreshAPICall made with " + credentials.get(Constants.SessionManagerConstants.KEY_USERNAME) + " " +
credentials.get(Constants.SessionManagerConstants.KEY_PASSWORD));
Log.v(LOG_TAG, "Priority set on refresh call is " + getPriority());
Log.v(LOG_TAG, "Tag for Call is " + getTag());
}
I set the priority of this request as high so that it gets triggered before the one that failed, so once we get a token the original call can then fire with the valid token.
Finally, on response I delete any other tasks with the retry tag (in case multiple API calls failed and made multiple retry calls, we don't want to overwrite the new token multiple times)
#Override
public void onTokenRefreshComplete(String token) {
VolleySingleton.getInstance(context).getRequestQueue().cancelAll(Constants.VolleyConstants.RETRY_TAG);
Log.v(LOG_TAG, "Cancelled all retry calls");
SessionManager sessionManager = new SessionManager(context);
sessionManager.setStoredToken(token);
Log.v(LOG_TAG, "Logged new token");
}
Unfortunately, the LogCat is showing me that all the retries are happening before we use the token. The token is coming back successfully, but it's obvious that the IMMEDIATE priority is having no effect on the order that the queue dispatches the calls.
Any help on how to ensure my RefreshAPICall is fired before the other tasks would be greatly appreciated. I'm wondering if Volley considers the RefreshAPICall as a subtask of the original failed task, and so it attempts to call that original task for its number of retrys until those are out, and then fires off the RefreshAPICall.
LogCat (not sure how to make this look pretty):
05-05 16:12:07.145: E/Volley(1972): [137] BasicNetwork.performRequest:
Unexpected response code **401 for https://url.me/api/get_friends**
05-05 16:12:07.145: V/TokenRetryPolicy(1972): Initiating a retry
05-05 16:12:07.145: V/TokenRetryPolicy(1972): AuthFailureError found!
05-05 16:12:07.146: V/VolleyUser(1972): refresh token task called
05-05 16:12:07.146: V/RefreshAPICall(1972): RefreshAPICall made with username user_password
05-05 16:12:07.147: V/RefreshAPICall(1972): Priority set on refresh call is HIGH
05-05 16:12:07.147: V/RefreshAPICall(1972): Tag for Call is retry
05-05 16:12:07.265: E/Volley(1972): [137] BasicNetwork.performRequest: Unexpected response code **401 for https://url.me/api/get_friends**
05-05 16:12:07.265: V/TokenRetryPolicy(1972): Initiating a retry
05-05 16:12:07.265: V/TokenRetryPolicy(1972): AuthFailureError found!
05-05 16:12:07.265: V/VolleyUser(1972): refresh token task called
05-05 16:12:07.265: V/RefreshAPICall(1972): RefreshAPICall made with user user_password
05-05 16:12:07.265: V/RefreshAPICall(1972): Priority set on refresh call is HIGH
05-05 16:12:07.265: V/RefreshAPICall(1972): Tag for Call is retry
05-05 16:12:07.265: V/TokenRetryPolicy(1972): No attempt remaining, ERROR
05-05 16:12:08.219: I/Choreographer(1972): Skipped 324 frames! The application may be doing too much work on its main thread.
05-05 16:12:08.230: V/RefreshAPICall(1972): Response from server on refresh is: {"status":"success","token":"d5792e18c0e1acb3ad507dbae854eb2cdc5962a2c1b610a6b77e3bc3033c7f64"}
05-05 16:12:08.230: V/VolleyUser(1972): Token from return is: d5792e18c0e1acb3ad507dbae854eb2cdc5962a2c1b610a6b77e3bc3033c7f64
05-05 16:12:08.231: V/TokenRetryPolicy(1972): Cancelled all retry calls
05-05 16:12:08.257: V/SessionManager(1972): New Token In SharedPref is: d5792e18c0e1acb3ad507dbae854eb2cdc5962a2c1b610a6b77e3bc3033c7f64
05-05 16:12:08.257: V/TokenRetryPolicy(1972): Logged new token
Posting an answer now that I found a half-decent way to handle token refreshing on retry.
When I create my general (most common) API call with Volley, I save a reference to the call in case it fails, and pass it to my retry policy.
public GeneralAPICall(int method, String url, Map<String, String> params, Context context, Response.Listener<JSONObject> responseListener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
sessionManager = SessionManager.getmInstance(context);
HashMap<String, String> credentials = sessionManager.getUserDetails(); // Get the user's credentials for authentication
this.listener = responseListener;
this.params = params;
// Encode the user's username and token
String loginEncoded = new String(Base64.encode((credentials.get(Constants.SessionManagerConstants.KEY_USERNAME)
+ Constants.APIConstants.Characters.CHAR_COLON
+ credentials.get(Constants.SessionManagerConstants.KEY_TOKEN)).getBytes(), Base64.NO_WRAP));
this.headers.put(Constants.APIConstants.BasicAuth.AUTHORIZATION, Constants.APIConstants.BasicAuth.BASIC + loginEncoded); // Set the encoded information as the header
setRetryPolicy(new TokenRetryPolicy(context, this)); //passing "this" saves the reference
}
Then, in my retry policy class (which simply extends the DefaultRetryPolicy, when I receive a 401 error telling me I need a new token, I shoot off a refreshToken call to get a new one.
public class TokenRetryPolicy extends DefaultRetryPolicy implements IRefreshTokenReturn{
...
#Override
public void retry(VolleyError error) throws VolleyError {
mCurrentRetryCount++; //increment our retry count
mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
if (error instanceof AuthFailureError && sessionManager.isLoggedIn()) {
mCurrentRetryCount = mMaxNumRetries + 1; // Don't retry anymore, it's pointless
VolleyUser.refreshTokenTask(context, this); // Get new token
} if (!hasAttemptRemaining()) {
Log.v(LOG_TAG, "No attempt remaining, ERROR");
throw error;
}
}
...
}
Once that call returns, I handle the response in my retry policy class. I modify the call that failed, giving it the new token (after storing the token in SharedPrefs) to authenticate itself, and then fire it off again!
#Override
public void onTokenRefreshComplete(String token, String expiration) {
sessionManager.setStoredToken(token, expiration);
HashMap<String, String> credentials = sessionManager.getUserDetails(); //get the user's credentials for authentication
//encode the user's username and token
String loginEncoded = new String(Base64.encode((credentials.get(Constants.SessionManagerConstants.KEY_USERNAME)
+ Constants.APIConstants.Characters.CHAR_COLON
+ credentials.get(Constants.SessionManagerConstants.KEY_TOKEN)).getBytes(), Base64.NO_WRAP));
Log.v(LOG_TAG, loginEncoded); //TODO: remove
callThatFailed.setHeaders(Constants.APIConstants.BasicAuth.AUTHORIZATION, Constants.APIConstants.BasicAuth.BASIC + loginEncoded); //modify "old, failed" call - set the encoded information as the header
VolleySingleton.getInstance(context).getRequestQueue().add(callThatFailed);
Log.v(LOG_TAG, "fired off new call");
}
This implementation works great for me.
However, I should note that this situation shouldn't happen much because I learned that I should check if my token has expired before making any API call. This is possible by storing an expiration time (returned from the server) in SharedPrefs, and seeing if current_time - expiration time < some_time, with some_time being the amount of time you would like to get a new token prior to it expiring, for me 10 seconds.
Hope this helps somebody out there, and if I'm wrong about anything, please comment!
The strategy I am using now is to add a refreshToken to the failed retry. This is a custom failure retry.
public class CustomRetryPolicy implements RetryPolicy
{
private static final String TAG = "Refresh";
private Request request;
/**
* The current timeout in milliseconds.
*/
private int mCurrentTimeoutMs;
/**
* The current retry count.
*/
private int mCurrentRetryCount;
/**
* The maximum number of attempts.
*/
private final int mMaxNumRetries;
/**
* The backoff multiplier for the policy.
*/
private final float mBackoffMultiplier;
/**
* The default socket timeout in milliseconds
*/
public static final int DEFAULT_TIMEOUT_MS = 2500;
/**
* The default number of retries
*/
public static final int DEFAULT_MAX_RETRIES = 1;
/**
* The default backoff multiplier
*/
public static final float DEFAULT_BACKOFF_MULT = 1f;
/**
* Constructs a new retry policy using the default timeouts.
*/
public CustomRetryPolicy() {
this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT);
}
/**
* Constructs a new retry policy.
*
* #param initialTimeoutMs The initial timeout for the policy.
* #param maxNumRetries The maximum number of retries.
* #param backoffMultiplier Backoff multiplier for the policy.
*/
public CustomRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {
mCurrentTimeoutMs = initialTimeoutMs;
mMaxNumRetries = maxNumRetries;
mBackoffMultiplier = backoffMultiplier;
}
/**
* Returns the current timeout.
*/
#Override
public int getCurrentTimeout() {
return mCurrentTimeoutMs;
}
/**
* Returns the current retry count.
*/
#Override
public int getCurrentRetryCount() {
return mCurrentRetryCount;
}
/**
* Returns the backoff multiplier for the policy.
*/
public float getBackoffMultiplier() {
return mBackoffMultiplier;
}
/**
* Prepares for the next retry by applying a backoff to the timeout.
*
* #param error The error code of the last attempt.
*/
#SuppressWarnings("unchecked")
#Override
public void retry(VolleyError error) throws VolleyError {
mCurrentRetryCount++;
mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
if (!hasAttemptRemaining()) {
throw error;
}
//401 and 403
if (error instanceof AuthFailureError) {//Just token invalid,refresh token
AuthFailureError er = (AuthFailureError) error;
if (er.networkResponse != null && er.networkResponse.statusCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
//Count is used to reset the flag
RefreshTokenManager instance = RefreshTokenManager.getInstance();
instance.increaseCount();
CUtils.logD(TAG, "come retry count: " + instance.getCount());
boolean ok = instance.refreshToken();
if (ok) {
Map<String, String> headers = request.getHeaders();
String[] tokens = instance.getTokens();
headers.put("token", tokens[0]);
Log.d(TAG, "retry:success");
} else {
throw error;
}
}
}
}
/**
* Returns true if this policy has attempts remaining, false otherwise.
*/
protected boolean hasAttemptRemaining() {
return mCurrentRetryCount <= mMaxNumRetries;
}
public Request getRequest() {
return request;
}
public void setRequest(Request request) {
this.request = request;
}
}
RefreshToken
public class RefreshTokenManager {
private static final String TAG = "Refresh";
private static RefreshTokenManager instance;
private final RefreshFlag flag;
/**
*retry count
*/
private AtomicInteger count = new AtomicInteger();
public int getCount() {
return count.get();
}
public int increaseCount() {
return count.getAndIncrement();
}
public void resetCount() {
this.count.set(0);
}
/**
* 锁
*/
private Lock lock;
public static RefreshTokenManager getInstance() {
synchronized (RefreshTokenManager.class) {
if (instance == null) {
synchronized (RefreshTokenManager.class) {
instance = new RefreshTokenManager();
}
}
}
return instance;
}
private RefreshTokenManager() {
flag = new RefreshFlag();
lock = new ReentrantLock();
}
public void resetFlag() {
lock.lock();
RefreshFlag flag = getFlag();
flag.resetFlag();
lock.unlock();
}
protected boolean refreshToken() {
lock.lock();
RefreshFlag flag = getFlag();
//Reset the flag so that the next time the token fails, it can enter normally.
if (flag.isFailure()) {
if (count.decrementAndGet() == 0) {
resetFlag();
}
lock.unlock();
return false;
} else if (flag.isSuccess()) {
CUtils.logD(TAG, "decrease retry count: " + instance.getCount());
if (count.decrementAndGet() == 0) {
count.incrementAndGet();
flag.resetFlag();
} else {
lock.unlock();
return true;
}
}
// refreshToken is doing.
flag.setDoing();
//Upload refresh_token and get the response from the server
String response = postRefreshTokenRequest();
CUtils.logD(TAG, "refreshToken: response " + response);
if (!TextUtils.isEmpty(response)) {
try {
JSONObject jsonObject = new JSONObject(response);
JSONObject data = jsonObject.optJSONObject("data");
if (data != null) {
String token = data.optString("token");
String refreshToken = data.optString("refresh_token");
CUtils.logD(TAG, "refreshToken: token : " + token + "\n" + "refresh_token : " + refreshToken);
if (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(refreshToken)) {
//success,save token and refresh_token
saveTokens(token, refreshToken);
CUtils.logD(TAG, "run: success notify ");
flag.setSuccess();
if (count.decrementAndGet() == 0) {
resetFlag();
}
CUtils.logD(TAG, "decrease retry count: " + instance.getCount());
lock.unlock();
return true;
}
}
} catch (Exception e) {
CUtils.logE(e);
}
}
//delete local token and refresh_token
removeTokens();
flag.setFailure();
count.decrementAndGet();
CUtils.logD(TAG, "decrease retry count: " + instance.getCount());
lock.unlock();
CUtils.logD(TAG, "run: fail notify ");
return false;
}
private RefreshFlag getFlag() {
return flag;
}
}
This is the flag
public final class RefreshFlag {
private static final int FLAG_SUCCESS = 0x01;
private static final int FLAG_DOING = 0x11;
private static final int FLAG_FAILURE = 0x10;
private static final int FLAG_INIT = 0x00;
/**
* flag 标志位
*/
private int flag = FLAG_INIT;
public boolean isDoingLocked() {
return flag == FLAG_DOING;
}
public void setDoing() {
flag = FLAG_DOING;
}
public void setSuccess() {
flag = FLAG_SUCCESS;
}
public void setFailure() {
flag = FLAG_FAILURE;
}
public boolean isSuccess() {
return flag == FLAG_SUCCESS;
}
public boolean isFailure() {
return flag == FLAG_FAILURE;
}
public void resetFlag() {
flag = FLAG_INIT;
}
}
I know this post this old, but posting my solution after other solutions suggested didn't help me.
Note - I did try Brandon's method given above, i.e., extending DefaultRetryPolicy. But it's fields are private, so didn't want to implement the whole class, there had to be a better way.
So I write the code in the CustomRequest class extending Request. Here are relevant snippets -
Store tokens in login response -
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
...
//if oauth data is sent with response, store in SharedPrefs
...
}
If access token has expired -
#Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
...
if (volleyError instanceof NoConnectionError) {
//i know, there has to be a better way than checking this.
//will work on it later
if(volleyError.getMessage().equalsIgnoreCase("java.io.IOException: No authentication challenges found")) {
String accessToken = getNewAccessToken();//synchronous call
//retry
if(accessToken != null) {
//IMP: this is the statement which will retry the request manually
NetworkHelper.get(mContext).getRequestQueue().add(this);
}
}
}
...
}
Attach access token to request -
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
...
String accesssToken = //get from SharedPrefs
headers.put("Authorization", "Bearer " +accessToken);
...
}
Going to login screen if refresh token is invalid -
private void showLogin(){
//stop all current requests
//cancelAllRequests();
Intent intent = new Intent(mContext, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivity(intent);
}
Getting new access token using refresh token. This has to be a synchronous method using RequestFuture -
private String getNewAccessToken(){
...
//get new access token from server and store in SharedPrefs
...
//also return the new token so that we know if we need to retry or not
return newAccessToken;
}
HTH

Google Glass GDK authentication using Java

I was testing the authentication for my GDK Glassware :
This is my code:
===================================================================================
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.Lists;
import com.google.api.services.mirror.Mirror;
import com.google.api.services.mirror.model.Account;
import com.google.api.services.mirror.model.AuthToken;
public class InsertAccountWithJava {
/** Email of the Service Account */
private static final String SERVICE_ACCOUNT_EMAIL =
"540223414844-tj91ijj3u9**********#developer.gserviceaccount.com ";
/** Path to the Service Account's Private Key file */
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH =
"C:/Users/Yuan/Desktop/eyenotes-847a787fecec.p12";
/** The account type, usually based on your company or app's package. */
private static final String ACCOUNT_TYPE = "com.myapplication";
/** The Mirror API scopes needed to access the API. */
private static final List<String> MIRROR_ACCOUNT_SCOPES =Arrays.asList(
"https://www.googleapis.com/auth/glass.thirdpartyauth");
public static void main(String[] args) {
try {
Mirror mirror = getMirrorService();
createAccount(mirror, "6164da1******", "zhongmeiCM", "com.myapplication", "747dab3e60dd8cd45595767580040538c8a29fcf");
} catch (GeneralSecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
/**
* Build and returns a Mirror service object authorized with the service accounts.
*
* #return Mirror service object that is ready to make requests.
*/
public static Mirror getMirrorService() throws GeneralSecurityException, IOException, URISyntaxException {
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(MIRROR_ACCOUNT_SCOPES)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
.build();
Mirror service = new Mirror.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential).build();
return service;
}
/**
* Creates an account and causes it to be synched up with the user's Glass.
* This example only supports one auth token; modify it if you need to add
* more than one, or to add features or user data or the password field.
*
* #param mirror the service returned by getMirrorService()
* #param userToken the user token sent to your auth callback URL
* #param accountName the account name for this particular user
* #param authTokenType the type of the auth token (chosen by you)
* #param authToken the auth token
*/
public static void createAccount(Mirror mirror, String userToken, String accountName,
String authTokenType, String authToken) {
try {
Account account = new Account();
List<AuthToken> authTokens = Lists.newArrayList();
AuthToken authToken1 = new AuthToken().setType(authTokenType).setAuthToken(authToken);
authTokens.add(authToken1);
account.setAuthTokens(authTokens);
account.setPassword("123456");
mirror.accounts().insert(
userToken, ACCOUNT_TYPE, accountName, account).execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
=====================================================================================
But I get an exception:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Invalid Value",
"reason" : "invalid"
}, {
"domain" : "global",
"message" : "Invalid Value",
"reason" : "invalid"
} ],
"message" : "Invalid Value"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
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:312)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1049)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at TestInsert.createAccount(TestInsert.java:92)
at TestInsert.main(TestInsert.java:39)
Question 1.please tell me how to generate the parameter:authToken,and what's the difference between authToken and accessToken ?
Question 2.what's the problem with my test code ? When can i get the Exception above.
authToken is an arbitrary String that you can define yourself. accessToken, on the other hand, is a token given to you during the authentication process. It is passed to the Google Mirror API to give your application access to user data.
Refer to the selected answer to this post.

Invalid_grant, Invalid code in google OAuth2

I am trying to obtain basic user profile information using Google OAuth2 API but it fails while trying to fetch the access/refresh tokens saying Invalid_grant and error description Invalid Code. Following is my code to fetch the token
public static String getUserInfoJson(final String authCode) throws IOException{
GoogleTokenResponse response = flow.newTokenRequest(authCode)
.setRedirectUri(CALLBACK_URI)
.execute();
Credential credential = flow.createAndStoreCredential(response,
null);
final HttpRequestFactory requestFactory = HTTP_TRANSPORT
.createRequestFactory(credential);
// Make an authenticated request
final GenericUrl url = new GenericUrl(USER_INFO_URL);
final HttpRequest request = requestFactory.buildGetRequest(url);
request.getHeaders().setContentType("application/json");
final String jsonIdentity = request.execute().parseAsString();
return jsonIdentity;
}
Following is my code to create the authCode
private static final String CLIENT_ID = "CLIENT_ID_BUT_NOT_EMAIL_ID"; //Not emailid
private static final String CLIENT_SECRET = "SecretKey";
private static final String CALLBACK_URI = "http://localhost:8080/Spring4MVCHelloWorld/OAuthRedirect";
private static final String ACCESS_TYPE = "offline";
private static final Iterable<String> SCOPE = Arrays
.asList("https://www.googleapis.com/auth/userinfo.profile;https://www.googleapis.com/auth/userinfo.email"
.split(";"));
private static final String USER_INFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo";
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private String stateToken;
private static GoogleAuthorizationCodeFlow flow;
public GoogleAuthHelper() {
flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT,
JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, SCOPE)
.setAccessType(ACCESS_TYPE)
.build();
generateStateToken();
}
public String buildLoginUrl() {
final GoogleAuthorizationCodeRequestUrl url = flow
.newAuthorizationUrl();
return url.setRedirectUri(CALLBACK_URI).setState(stateToken).build();
}
private void generateStateToken() {
SecureRandom sr1 = new SecureRandom();
stateToken = "google;" + sr1.nextInt();
}
public String getStateToken() {
return stateToken;
}
User is redirected successfully to the redirect URL but the subsequent call to getUserInfoJson fails with a a 400 response.
I have gone through many SO questions similar to this to no avail.

Twitter API upgrade for Windows Phone

I have tweet poster in my application which uses oAuth 1.0 which will retire soon and will be non functional. I have to upgrade my API to 1.1. Twitter development center says that, If oAuth is used by your application, you can easily transaction to 1.1 by only updating your API endpoint. What exactly is API endpoint?
Here I'm having hard understanding about API endpoint. I think my asyncronous post call URL must be upgraded.
Here is the relevant codes which I think that might include the answer;
private void btnPostTweet_Click(object sender, RoutedEventArgs e)
{
namebocx.Text = userScreenName;
if (txtBoxNewTweet.Text.Trim().Length == 0) { return; }
var credentials = new OAuthCredentials
{
Type = OAuthType.ProtectedResource,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
ConsumerKey = TwitterSettings.consumerKey,
ConsumerSecret = TwitterSettings.consumerKeySecret,
Token = this.accessToken,
TokenSecret = this.accessTokenSecret,
Version = "1.0"
};
var restClient = new RestClient
{
Authority = TwitterSettings.StatusUpdateUrl,
HasElevatedPermissions = true,
Credentials = credentials,
Method = WebMethod.Post
};
restClient.AddHeader("Content-Type", "application/x-www-form-urlencoded");
// Create a Rest Request and fire it
var restRequest = new RestRequest
{
Path = "1/statuses/update.xml?status=" + txtBoxNewTweet.Text //Here must be endpoint of Api??
};
var ByteData = Encoding.UTF8.GetBytes(txtBoxNewTweet.Text);
restRequest.AddPostContent(ByteData);
restClient.BeginRequest(restRequest, new RestCallback(PostTweetRequestCallback));
}
}
and also here is the authentication settings:
public class TwitterSettings
{
public static string RequestTokenUri = "https://api.twitter.com/oauth/request_token";
public static string AuthorizeUri = "https://api.twitter.com/oauth/authorize";
public static string AccessTokenUri = "https://api.twitter.com/oauth/access_token";
public static string CallbackUri = "http://www.google.com";
public static string StatusUpdateUrl { get { return "http://api.twitter.com"; } }
public static string consumerKey = "myconsumerkeyhere";
public static string consumerKeySecret = "myconsumersecrethere";
public static string oAuthVersion = "1.0a";
}
Here what twitter says me to replace with this instead of written in my code;
https://api.twitter.com/1.1/statuses/update.json
and some parameters told here -->> https://dev.twitter.com/docs/api/1.1/post/statuses/update
How should I update my API endpoint, what kind of changes do I have to do?
If you can help me, I really appreciate
You can change this:
Path = "1/statuses/update.xml?status=" + txtBoxNewTweet.Text
//Here must be endpoint of Api??
to this:
Path = "1.1/statuses/update.json?status=" + txtBoxNewTweet.Text
//Here must be endpoint of Api??