protected void verifyProviderCredentialsForUser(WritableSession session, User user) {
    List<UserAuthData> authData = user.getAuthData();
    UserProviderCredentialsMap credentials = session.getUserProviderCredentials();

    if (credentials != null) {

      if (authData != null) {
        Map<AuthProviderType, UserProviderCredentials> validCreds =
            new LinkedHashMap<AuthProviderType, UserProviderCredentials>();
        for (UserAuthData userAuthData : authData) {
          UserProviderCredentials creds = credentials.get(userAuthData.getAuthProviderType());
          if (creds != null) {
            validCreds.put(userAuthData.getAuthProviderType(), creds);
          }
        }

        // Clear and reset
        credentials.removeAll();

        Set<Entry<AuthProviderType, UserProviderCredentials>> entrySet = validCreds.entrySet();

        for (Entry<AuthProviderType, UserProviderCredentials> entry : entrySet) {
          credentials.put(entry.getKey(), entry.getValue());
        }
      } else {
        credentials.removeAll();
      }

      // Set back to session
      session.setUserProviderCredentials(credentials);
    }
  }
  @Override
  public WritableSession loadSession(String endpoint, String key, String secret)
      throws SocializeException {

    if (sessionPersister != null) {
      WritableSession loaded = sessionPersister.load(context);

      // Verify that the key/secret matches
      if (loaded != null) {

        String loadedKey = loaded.getConsumerKey();
        String loadedSecret = loaded.getConsumerSecret();
        String loadedHost = loaded.getHost();

        String host = config.getProperty(SocializeConfig.API_HOST);

        if (loadedKey != null
            && loadedKey.equals(key)
            && loadedSecret != null
            && loadedSecret.equals(secret)
            && loadedHost != null
            && loadedHost.equals(host)) {

          return loaded;
        }
      }
    }
    return null;
  }
  protected WritableSession setProviderCredentialsForUser(
      AuthProviderData data, WritableSession session) {
    AuthProviderInfo info = data.getAuthProviderInfo();

    if (info != null) {
      DefaultUserProviderCredentials userProviderCredentials = new DefaultUserProviderCredentials();
      userProviderCredentials.setAccessToken(data.getToken3rdParty());
      userProviderCredentials.setTokenSecret(data.getSecret3rdParty());
      userProviderCredentials.setUserId(data.getUserId3rdParty());
      userProviderCredentials.setAuthProviderInfo(data.getAuthProviderInfo());

      session.getUserProviderCredentials().put(info.getType(), userProviderCredentials);
    } else {
      // Legacy
      session = null;
    }

    return session;
  }
  @Override
  public SocializeSession authenticate(
      String endpoint, String key, String secret, AuthProviderData data, String uuid)
      throws SocializeException {
    try {
      SessionLock.lock();

      WritableSession session = loadSession(endpoint, key, secret);

      if (session != null) {

        if (validateSession(session, data)) {
          return session;
        } else {
          session = setProviderCredentialsForUser(data, session);
        }
      }

      if (session == null) {
        session = sessionFactory.create(key, secret, data);
      }

      endpoint = prepareEndpoint(session, endpoint, true);

      if (!clientFactory.isDestroyed()) {

        HttpClient client = clientFactory.getClient();

        HttpEntity entity = null;

        try {
          HttpUriRequest request = requestFactory.getAuthRequest(session, endpoint, uuid, data);

          if (logger != null && logger.isDebugEnabled()) {
            logger.debug("Calling authenticate endpoint for device [" + uuid + "]");
          }

          HttpResponse response = executeRequest(client, request);

          entity = response.getEntity();

          if (httpUtils.isHttpError(response)) {

            if (sessionPersister != null && httpUtils.isAuthError(response)) {
              sessionPersister.delete(context);
            }

            String msg = ioUtils.readSafe(entity.getContent());

            throw new SocializeApiError(httpUtils, response.getStatusLine().getStatusCode(), msg);
          } else {

            JSONObject json = jsonParser.parseObject(entity.getContent());

            User user = userFactory.fromJSON(json.getJSONObject("user"));

            String oauth_token = json.getString("oauth_token");
            String oauth_token_secret = json.getString("oauth_token_secret");

            if (StringUtils.isEmpty(oauth_token)) {
              throw new SocializeException("oauth_token was empty in response from server");
            }

            if (StringUtils.isEmpty(oauth_token_secret)) {
              throw new SocializeException("oauth_token_secret was empty in response from server");
            }

            session.setConsumerToken(oauth_token);
            session.setConsumerTokenSecret(oauth_token_secret);
            session.setUser(user);

            setProviderCredentialsForUser(data, session);

            // Ensure the user credentials match the user auth data returned from the server
            verifyProviderCredentialsForUser(session, user);

            saveSession(session);
          }
        } catch (Exception e) {
          throw SocializeException.wrap(e);
        } finally {
          closeEntity(entity);
        }
      } else {
        if (logger != null) {
          logger.warn("Attempt to access HttpClientFactory that was already destroyed");
        }
      }

      return session;
    } finally {
      SessionLock.unlock();
    }
  }