public void removeAccessTokenUsingRefreshToken(String refreshToken) {
    String tokenId = null;

    try {
      tokenId =
          dynamoDBTemplate.queryUnique(
              schema.getAccessTableName(),
              schema.getAccessIndexRefreshToken(), //
              Collections.singletonMap(
                  schema.getAccessColumnRefreshToken(),
                  new Condition()
                      .withAttributeValueList(new AttributeValue(extractTokenKey(refreshToken)))
                      .withComparisonOperator(ComparisonOperator.EQ)), //
              new ObjectExtractor<String>() {

                public String extract(Map<String, AttributeValue> values) {
                  return values.get(schema.getAccessColumnTokenId()).getS();
                }
              },
              schema.getAccessColumnTokenId());
    } catch (EmptyResultDataAccessException | IncorrectResultSizeDataAccessException e) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Failed to find access token for refresh token " + refreshToken);
      }
    }

    if (tokenId == null) {
      return;
    }

    dynamoDBTemplate.delete(
        schema.getAccessTableName(),
        Collections.singletonMap(schema.getAccessColumnTokenId(), new AttributeValue(tokenId)));
  }
  private Collection<OAuth2AccessToken> loadTokensByClientAndUserIndex(
      Map<String, Condition> keyCondition, boolean filterOutNullUsers) {
    List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();

    List<String> accessTokenIds = null;
    try {
      accessTokenIds =
          dynamoDBTemplate.query(
              schema.getAccessTableName(),
              schema.getAccessIndexClientIdAndUserName(),
              keyCondition, //
              new ObjectExtractor<String>() {

                public String extract(Map<String, AttributeValue> values) {
                  return values.get(schema.getAccessColumnTokenId()).getS();
                }
              },
              schema.getAccessColumnTokenId());

      List<Map<String, AttributeValue>> keys =
          new ArrayList<Map<String, AttributeValue>>(accessTokenIds.size());
      for (String accessTokenId : accessTokenIds) {
        keys.add(
            Collections.singletonMap(
                schema.getAccessColumnTokenId(), new AttributeValue(accessTokenId)));
      }
      if (filterOutNullUsers) {
        accessTokens =
            dynamoDBTemplate.batchGet(
                schema.getAccessTableName(), //
                new KeysAndAttributes()
                    .withKeys(keys)
                    .withConsistentRead(true)
                    .withAttributesToGet(
                        schema.getAccessColumnTokenId(),
                        schema.getAccessColumnToken(),
                        schema.getAccessColumnIsNullUser()), //
                new NonNullUserSafeAccessTokenExtractor());
      } else {
        accessTokens =
            dynamoDBTemplate.batchGet(
                schema.getAccessTableName(), //
                new KeysAndAttributes()
                    .withKeys(keys)
                    .withConsistentRead(true)
                    .withAttributesToGet(
                        schema.getAccessColumnTokenId(), schema.getAccessColumnToken()), //
                new SafeAccessTokenExtractor());
      }
    } catch (EmptyResultDataAccessException e) {
      if (LOG.isInfoEnabled()) {
        LOG.info("Failed to find access token for " + keyCondition.toString());
      }
    }
    accessTokens = removeNulls(accessTokens);

    return accessTokens;
  }
  public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
    OAuth2AccessToken accessToken = null;

    String key = authenticationKeyGenerator.extractKey(authentication);
    try {
      String accessTokenId =
          dynamoDBTemplate.queryUnique(
              schema.getAccessTableName(),
              schema.getAccessIndexAuthenticationId(), //
              Collections.singletonMap(
                  schema.getAccessColumnAuthenticationId(),
                  new Condition()
                      .withComparisonOperator(ComparisonOperator.EQ)
                      .withAttributeValueList(new AttributeValue(key))), //
              new ObjectExtractor<String>() {

                public String extract(Map<String, AttributeValue> values) {
                  return values.get(schema.getAccessColumnTokenId()).getS();
                }
              });
      accessToken =
          dynamoDBTemplate.get(
              schema.getAccessTableName(),
              Collections.singletonMap(
                  schema.getAccessColumnTokenId(), new AttributeValue(accessTokenId)),
              new ObjectExtractor<OAuth2AccessToken>() {

                public OAuth2AccessToken extract(Map<String, AttributeValue> values) {
                  return deserializeAccessToken(values.get(schema.getAccessColumnToken()).getB());
                }
              });
    } catch (EmptyResultDataAccessException | IncorrectResultSizeDataAccessException e) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Failed to find access token for authentication " + authentication);
      }
    } catch (IllegalArgumentException e) {
      LOG.error("Could not extract access token for authentication " + authentication, e);
    }

    if (accessToken != null
        && !key.equals(
            authenticationKeyGenerator.extractKey(readAuthentication(accessToken.getValue())))) {
      // Keep the store consistent (maybe the same user is represented by this authentication but
      // the details have
      // changed)
      storeAccessToken(accessToken, authentication);
    }
    return accessToken;
  }
  public OAuth2Authentication readAuthenticationForRefreshToken(String value) {
    OAuth2Authentication authentication = null;

    try {
      authentication =
          dynamoDBTemplate.get(
              schema.getRefreshTableName(),
              Collections.singletonMap(
                  schema.getRefreshColumnTokenId(), new AttributeValue(extractTokenKey(value))),
              new ObjectExtractor<OAuth2Authentication>() {

                public OAuth2Authentication extract(Map<String, AttributeValue> values) {
                  return deserializeAuthentication(
                      values.get(schema.getRefreshColumnAuthentication()).getB());
                }
              },
              schema.getRefreshColumnAuthentication());
    } catch (EmptyResultDataAccessException e) {
      if (LOG.isInfoEnabled()) {
        LOG.info("Failed to find refresh token for token " + value);
      }
    } catch (IllegalArgumentException e) {
      LOG.warn("Failed to deserialize authentication for " + value, e);
      removeRefreshToken(value);
    }

    return authentication;
  }
  public OAuth2AccessToken readAccessToken(String tokenValue) {
    OAuth2AccessToken accessToken = null;

    try {
      accessToken =
          dynamoDBTemplate.get(
              schema.getAccessTableName(),
              Collections.singletonMap(
                  schema.getAccessColumnTokenId(), new AttributeValue(extractTokenKey(tokenValue))),
              new ObjectExtractor<OAuth2AccessToken>() {

                public OAuth2AccessToken extract(Map<String, AttributeValue> values) {
                  return deserializeAccessToken(values.get(schema.getAccessColumnToken()).getB());
                }
              },
              schema.getAccessColumnToken());
    } catch (EmptyResultDataAccessException e) {
      if (LOG.isInfoEnabled()) {
        LOG.info("Failed to find access token for token " + tokenValue);
      }
    } catch (IllegalArgumentException e) {
      LOG.warn("Failed to deserialize access token for " + tokenValue, e);
      removeAccessToken(tokenValue);
    }

    return accessToken;
  }
  public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
    String refreshToken = null;
    if (token.getRefreshToken() != null) {
      refreshToken = token.getRefreshToken().getValue();
    }

    // the JdbcTokenStore removes the existing token for this token_id [if it exists]
    // We'll avoid doing so for now, unless a compelling reason to do otherwise presents itself
    //        if (readAccessToken(token.getValue()) != null) {
    //            removeAccessToken(token.getValue());
    //        }

    Map<String, AttributeValueUpdate> updates = new HashMap<String, AttributeValueUpdate>();
    updates.put(
        schema.getAccessColumnToken(),
        new AttributeValueUpdate(
            new AttributeValue().withB(serializeAccessToken(token)), AttributeAction.PUT));
    DynamoDBUtils.nullSafeUpdateS(
        updates,
        schema.getAccessColumnAuthenticationId(),
        authenticationKeyGenerator.extractKey(authentication));
    if (authentication.isClientOnly()
        || authentication.getName() == null
        || authentication.getName().length() == 0) {
      DynamoDBUtils.nullSafeUpdateS(
          updates, schema.getAccessColumnUserName(), schema.getAccessNullUserToken());
      updates.put(
          schema.getAccessColumnIsNullUser(),
          new AttributeValueUpdate(
              new AttributeValue().withN(schema.getAccessIsNullUserTrueToken()),
              AttributeAction.PUT));
    } else {
      DynamoDBUtils.nullSafeUpdateS(
          updates, schema.getAccessColumnUserName(), authentication.getName());
      DynamoDBUtils.nullSafeUpdateS(updates, schema.getAccessColumnIsNullUser(), null);
    }

    DynamoDBUtils.nullSafeUpdateS(
        updates, schema.getAccessColumnClientId(), authentication.getOAuth2Request().getClientId());
    updates.put(
        schema.getAccessColumnAuthentication(),
        new AttributeValueUpdate(
            new AttributeValue().withB(serializeAuthentication(authentication)),
            AttributeAction.PUT));
    DynamoDBUtils.nullSafeUpdateS(
        updates, schema.getAccessColumnRefreshToken(), extractTokenKey(refreshToken));

    dynamoDBTemplate.update(
        schema.getAccessTableName(), //
        Collections.singletonMap(
            schema.getAccessColumnTokenId(),
            new AttributeValue(extractTokenKey(token.getValue()))), //
        updates);
  }
  public void storeRefreshToken(
      OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
    Map<String, AttributeValueUpdate> updates = new HashMap<String, AttributeValueUpdate>();
    updates.put(
        schema.getRefreshColumnToken(),
        new AttributeValueUpdate(
            new AttributeValue().withB(serializeRefreshToken(refreshToken)), AttributeAction.PUT));
    updates.put(
        schema.getRefreshColumnAuthentication(),
        new AttributeValueUpdate(
            new AttributeValue().withB(serializeAuthentication(authentication)),
            AttributeAction.PUT));

    dynamoDBTemplate.update(
        schema.getRefreshTableName(), //
        Collections.singletonMap(
            schema.getRefreshColumnTokenId(),
            new AttributeValue(extractTokenKey(refreshToken.getValue()))), //
        updates);
  }
 public void removeRefreshToken(String token) {
   dynamoDBTemplate.delete(
       schema.getRefreshTableName(),
       Collections.singletonMap(
           schema.getRefreshColumnTokenId(), new AttributeValue(extractTokenKey(token))));
 }
 public void removeAccessToken(String tokenValue) {
   dynamoDBTemplate.delete(
       schema.getAccessTableName(),
       Collections.singletonMap(
           schema.getAccessColumnTokenId(), new AttributeValue(extractTokenKey(tokenValue))));
 }