Skip to content

Support RedisOAuth2AuthorizationService, which is an implementation of OAuth2AuthorizationService using Redis #1642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sinbom opened this issue Jun 13, 2024 · 1 comment
Assignees
Labels
status: duplicate A duplicate of another issue

Comments

@sinbom
Copy link

sinbom commented Jun 13, 2024

Expected Behavior
Support RedisOAuth2AuthorizationService, which is an implementation of OAuth2AuthorizationService using Redis.

Current Behavior
The following implementations of OAuth2AuthorizationService are currently supported: InMemoryOAuth2AuthorizationService, which uses application memory, and JdbcOAuth2AuthorizationService, which uses a relational database.

Context
i want to use an OAuth2AuthorizationService implementation that has persistence rather than application memory. I tried to use the JdbcOAuth2Authorization Service using a relational database, but I was using JPA in the project, so I have defined and used the JpaOAuth2AuthorizationService, an implementation customized by referring to the spring guide document.

However, as the data increased, I thought that there was a limit to efficiently query under various query conditions (state, authorization_code_value, access_token_value, etc...), and it was difficult to apply the index efficiently. Also, a separate scheduling task was required to delete expired data. So, I thought it might be more efficient to use an implementation using redis.

Oauth2AuthorizationService.findByToken

    @Nullable
    public OAuth2Authorization findByToken(String token, @Nullable OAuth2TokenType tokenType) {
        Assert.hasText(token, "token cannot be empty");
        List<SqlParameterValue> parameters = new ArrayList();
        if (tokenType == null) {
            parameters.add(new SqlParameterValue(12, token));
            parameters.add(mapToSqlParameter("authorization_code_value", token));
            parameters.add(mapToSqlParameter("access_token_value", token));
            parameters.add(mapToSqlParameter("oidc_id_token_value", token));
            parameters.add(mapToSqlParameter("refresh_token_value", token));
            parameters.add(mapToSqlParameter("user_code_value", token));
            parameters.add(mapToSqlParameter("device_code_value", token));
            return this.findBy("state = ? OR authorization_code_value = ? OR access_token_value = ? OR oidc_id_token_value = ? OR refresh_token_value = ? OR user_code_value = ? OR device_code_value = ?", parameters);
        } else if ("state".equals(tokenType.getValue())) {
            parameters.add(new SqlParameterValue(12, token));
            return this.findBy("state = ?", parameters);
        } else if ("code".equals(tokenType.getValue())) {
            parameters.add(mapToSqlParameter("authorization_code_value", token));
            return this.findBy("authorization_code_value = ?", parameters);
        } else if (OAuth2TokenType.ACCESS_TOKEN.equals(tokenType)) {
            parameters.add(mapToSqlParameter("access_token_value", token));
            return this.findBy("access_token_value = ?", parameters);
        } else if ("id_token".equals(tokenType.getValue())) {
            parameters.add(mapToSqlParameter("oidc_id_token_value", token));
            return this.findBy("oidc_id_token_value = ?", parameters);
        } else if (OAuth2TokenType.REFRESH_TOKEN.equals(tokenType)) {
            parameters.add(mapToSqlParameter("refresh_token_value", token));
            return this.findBy("refresh_token_value = ?", parameters);
        } else if ("user_code".equals(tokenType.getValue())) {
            parameters.add(mapToSqlParameter("user_code_value", token));
            return this.findBy("user_code_value = ?", parameters);
        } else if ("device_code".equals(tokenType.getValue())) {
            parameters.add(mapToSqlParameter("device_code_value", token));
            return this.findBy("device_code_value = ?", parameters);
        } else {
            return null;
        }
    }

JpaOAuth2AuthorizationService.findByToken

    @Override
    public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) {
        Assert.hasText(token, "token cannot be empty");

        Optional<Authorization> result;
        if (tokenType == null) {
            result = this.authorizationRepository.findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValueOrOidcIdTokenValueOrUserCodeValueOrDeviceCodeValue(token);
        } else if (OAuth2ParameterNames.STATE.equals(tokenType.getValue())) {
            result = this.authorizationRepository.findByState(token);
        } else if (OAuth2ParameterNames.CODE.equals(tokenType.getValue())) {
            result = this.authorizationRepository.findByAuthorizationCodeValue(token);
        } else if (OAuth2ParameterNames.ACCESS_TOKEN.equals(tokenType.getValue())) {
            result = this.authorizationRepository.findByAccessTokenValue(token);
        } else if (OAuth2ParameterNames.REFRESH_TOKEN.equals(tokenType.getValue())) {
            result = this.authorizationRepository.findByRefreshTokenValue(token);
        } else if (OidcParameterNames.ID_TOKEN.equals(tokenType.getValue())) {
            result = this.authorizationRepository.findByOidcIdTokenValue(token);
        } else if (OAuth2ParameterNames.USER_CODE.equals(tokenType.getValue())) {
            result = this.authorizationRepository.findByUserCodeValue(token);
        } else if (OAuth2ParameterNames.DEVICE_CODE.equals(tokenType.getValue())) {
            result = this.authorizationRepository.findByDeviceCodeValue(token);
        } else {
            result = Optional.empty();
        }

        return result.map(this::toObject).orElse(null);
    }

I think that expired tokens can be automatically deleted by applying TTL, and even if the data increases, it can be efficiently searched by storing them in key-value form without having to apply multiple indexes. Of course, I think Redis might not be the best choice if you need to lookup on a variety of conditions rather than just keys, but I think it's relatively efficient compared to implementing it using an RDBMS.

Do you have any plans to support the OAuth2AuthorizationService implementation using redis? If you don't have any plans to support it, I wonder why. Maybe I'm thinking about it all wrong?

@sinbom sinbom added the type: enhancement A general enhancement label Jun 13, 2024
@sinbom sinbom changed the title Support RedisOAuth2AuthorizationService that implementation of OAuth2AuthorizationService Support RedisOAuth2AuthorizationService, which is an implementation of OAuth2AuthorizationService using Redis Jun 13, 2024
@jgrandja
Copy link
Collaborator

Closing this as a duplicate of gh-1019. Also see gh-558 for more context.

@jgrandja jgrandja self-assigned this Jun 19, 2024
@jgrandja jgrandja added status: duplicate A duplicate of another issue and removed type: enhancement A general enhancement labels Jun 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

2 participants