class RefreshTokenProvider extends AbstractUserProvider {

    @Override
    public AccessToken getAccessToken(String googleIdentity, List<String> scopes) {
        // Fetch refresh token from the database
        RefreshToken refreshToken = null;
        try {
            refreshToken = (RefreshToken) AbstractDatabaseBackend.getInstance().get(RefreshToken.class, googleIdentity);
        }
        catch (DatabaseObjectNotFound e) {
            throw Status.PERMISSION_DENIED.withDescription(String.format(AUTHZ_ERROR_MESSAGE, googleIdentity)).asRuntimeException();
        }

        // Decrypt the refresh token's value
        byte[] encryptedValue = refreshToken.getValue();
        String decryptedValue = new String(AbstractEncryptionBackend.getInstance().decrypt(encryptedValue));

        // Load OAuth client secret
        GoogleClientSecrets clientSecrets = OauthClientSecretsLoader.getSecrets();

        // Generate a new access token
        TokenResponse response = null;
        try {
            response = new GoogleRefreshTokenRequest(
                new NetHttpTransport(),
                new JacksonFactory(),
                decryptedValue,
                clientSecrets.getDetails().getClientId(),
                clientSecrets.getDetails().getClientSecret()
            ).setScopes(scopes).execute();
        } catch (IOException e) {
            throw Status.PERMISSION_DENIED.withDescription(String.format(AUTHZ_ERROR_MESSAGE, googleIdentity)).asRuntimeException();
        }

        return new AccessToken(
            response.getAccessToken(),
                TimeUtils.currentTimeMillis() + response.getExpiresInSeconds() * 1000);
    }

}