Danidhsm
Danidhsm

Reputation: 91

How to persist OAuth2AuthorizedClient in redis-session

My project uses redis session with springboot session and spring security 5.1.10. I just migrated the old oauth2 implementation. Before, when I restarted the app I still had the access_token and refresh_token. With this implementation the user is logged in, but I loose the AuthorizedClients so loadAuthorizedClient function returns null after restarting. Also in production we have many containers with the same app. Is there any springboot stardard way to achieve this? like register some bean or something.

application.yml

    ...

    session:
        store-type: redis
        redis:
            namespace: spring:session:${spring.application.name}
    redis:
        host: ${redissession.host}
        password: ${redissession.password}
        port: ${redissession.port}

    security:
        oauth2:
            client:
                registration:
                    biocryptology:
                        provider: example
                        client-id: client
                        client-secret: xxx
                        client-authentication-method: basic
                        authorization-grant-type: authorization_code
                        redirect-uri-template: "{baseUrl}/login"
                        scope:
                            - openid
                provider:
                    example:
                        issuer-uri: https://....
    ...

Controller.java

        @Autowired
        private OAuth2AuthorizedClientService clientService;

        @GetMapping("/user")
        public String getOidcUserPrincipal() throws InvalidSessionException {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (!(authentication.getPrincipal() instanceof OidcUser)) {
                throw new InvalidSessionException();
            }

            OidcUser principal = ((OidcUser) authentication.getPrincipal());
            LOG.info("oidc: {}", principal.getName());

            OAuth2AuthenticationToken oauth2Token = (OAuth2AuthenticationToken) authentication;
            LOG.info("authentication: {}", oauth2Token);
            OAuth2AuthorizedClient client = clientService
                    .loadAuthorizedClient(oauth2Token.getAuthorizedClientRegistrationId(), authentication.getName());
            LOG.info("client: {}", client);

            return "logged";

        }

The goal is getting the access_token and refresh_token across containers, any other way without OAuth2AuthorizedClientService maybe?

EDIT:

        <!-- Spring -->
        <spring-cloud.version>Greenwich.SR5</spring-cloud.version>

Upvotes: 3

Views: 5631

Answers (1)

Danidhsm
Danidhsm

Reputation: 91

Registering a bean did the trick, it saves it in session, but then OAuth2AuthorizedClientService breaks down for every case and needs a workaround searching in session directly or using OAuth2AuthorizedClientRepository autowired:

    @Bean
    public OAuth2AuthorizedClientRepository authorizedClientRepository() {
        return new HttpSessionOAuth2AuthorizedClientRepository();
    }

controller.java

    @Autowired
    private OAuth2AuthorizedClientRepository clientRepository;

    @GetMapping("/user")
    public Map<String, Object> getOidcUserPrincipal(HttpServletRequest request) throws InvalidSessionException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!(authentication.getPrincipal() instanceof OidcUser)) {
            throw new InvalidSessionException();
        }

        OidcUser principal = ((OidcUser) authentication.getPrincipal());

        OAuth2AuthorizedClient client = clientRepository
                .loadAuthorizedClient(oauth2Token.getAuthorizedClientRegistrationId(), authentication, request);
        LOG.info("client: {}", client);
        if (Objects.nonNull(client)) {
            String token = client.getAccessToken().getTokenValue();
            String refreshtoken = client.getRefreshToken().getTokenValue();

            LOG.info("token: {} {}", token, refreshtoken);
        }

        return principal.getClaims();
    }

Upvotes: 5

Related Questions