2

I have setup the glass-java-starter project and encounter an issue in notification flow, which is handled by NotifyServlet.

I can't get the "credential" occasionally。

Below is the where I encounter the problem.

Credential credential = AuthUtil.getCredential(userId);

credential will be null after this line occasionally even I didn't restart the server

Once I got error, I can solve it by re-login to the website.

I am not sure whether there is a timeout for the "Credential" store, and if yes, how long is it, and how to handle the timeout, any practice to follow?

Further Update:

Some finding:

  • I found we can get the expiry time from Credential object as below

    credential.getExpiresInSeconds()

I can get a return value which is around 3600, right after I get the credential. So I think usually the expiry time of access token is 1 hr.

When I encounter the problem, I believe it just couple mins after I logged in, won't be longer than one hour.

  • Another point is, if the problem is about credential timeout, then I believe I can still get the credential object by following code, even the token stored in it is invalid, the credential object should be there.

    Credential credential = AuthUtil.getCredential(userId);

So I suspect the problem is in credential object store, I am not sure how current app store the credential, but even it is in memory, I think I should be able to get it as long as I don't restart the server. So don't know whey I encounter the "Null" return here

Community
  • 1
  • 1
fantasy8
  • 73
  • 6

1 Answers1

0

I suspect that your userId value is null. Because you shouldn't get null Credential after you've stored it for a specific userId.

Detailed Reason:

AuthUtil.getCredential(userId) returns a Credential if userId is not null and there is a stored Credential for incoming userId:

public static Credential getCredential(String userId) throws IOException {
  if (userId == null) {
    return null;
  } else {
    return AuthUtil.newAuthorizationCodeFlow().loadCredential(userId);
  }
}

If userId is not null then newAuthorizationCodeFlow is called and a GoogleAuthorizationCodeFlow instance is created:

public static AuthorizationCodeFlow newAuthorizationCodeFlow() throws IOException {
  // we have clientId and clientSecret here
  GoogleAuthorizationCodeFlow authCodeFlow = GoogleAuthorizationCodeFlow.Builder(new NetHttpTransport(), new JacksonFactory(), clientId, clientSecret, Collections.singleton(GLASS_SCOPE)).setAccessType("offline");
  authCodeFlow.setCredentialStore(store).build();
  return authCodeFlow ;
}

store instance that we used in newAuthorizationCodeFlow is a static object and we store all Credentials in that static object:

public static ListableMemoryCredentialStore store = new ListableMemoryCredentialStore();

If we go back to getCredential method again, you'll see loadCredential method call. This call hits ListableMemoryCredentialStore's load(String userId, Credential credential) method:

public boolean load(String userId, Credential credential) {
  lock.lock();
  try {
    MemoryPersistedCredential item = store.get(userId);
    if (item != null) {
      item.load(credential);
    }
    return item != null;
  } finally {
    lock.unlock();
  }
}

Thus stored Credentials can not be removed or null unless;

  1. Application restarts or
  2. Incoming userId is null or
  3. There is no Credential for incoming userId.

Edit: BTW expire time can not make a Credential NULL. Try to write accessToken, refreshToken and expireTime values to a file or database and read them at your CredentialStore. If you have the same problem again check your incoming userId.

For instance I'm storing them at a table and never got a problem as yours.

Devrim
  • 15,345
  • 4
  • 66
  • 74