javafacebookspring-socialspring-social-facebook

How to handle ExpiredAuthorizationException (The authorization has expired) in spring-social-facebook


I'm using spring-social-facebook and sometimes, after some time the authentication seems to expire and I get this exception:

org.springframework.social.ExpiredAuthorizationException: The authorization has expired.
    at org.springframework.social.facebook.api.impl.FacebookErrorHandler.handleFacebookError(FacebookErrorHandler.java:83)
    at org.springframework.social.facebook.api.impl.FacebookErrorHandler.handleError(FacebookErrorHandler.java:59)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:667)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:620)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:595)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:303)
    at org.springframework.social.facebook.api.impl.SocialContextTemplate.getSocialContext(SocialContextTemplate.java:120)

I don't know how to handle with this error...Would it be possible to automatically reconnect after the authentication expires?

Versions used:

 <dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-facebook</artifactId>
    <version>2.0.4.BUILD-SNAPSHOT</version>
</dependency>

<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-core</artifactId>
    <version>1.1.4.RELEASE</version>
</dependency>

I've found similar questions in SO:

Any help would be apreciated.


Solution

  • To fix this issue you must add a ReconnectFilter to the social configuration Java file:

        @Bean
        public ReconnectFilter apiExceptionHandler(UsersConnectionRepository usersConnectionRepository, UserIdSource userIdSource) {
            return new ReconnectFilter(usersConnectionRepository, userIdSource);
        }
    

    This ReconnectFilter depends on an UserIdSource Bean to retrieve the user information and refresh the connection. You must override it:

     @Override
        @Bean
        public UserIdSource getUserIdSource() {
            return new UserIdSource() {
                @Override
                public String getUserId() {
                    User user = getUser();
                    if (user == null) {
                        throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
                    }
                    return user.getId();
                }
            };
        }
    

    You can see the entire Social Config file below:

    @Configuration
    @PropertySource("classpath:application.properties")
    @EnableSocial
    public class SocialConfig  extends SocialConfigurerAdapter {
    
        @Override
        public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
            cfConfig.addConnectionFactory(new FacebookConnectionFactory(env.getProperty("facebook.appKey"), env.getProperty("facebook.appSecret")));
        }
    
    
        @Bean
        public UsersConnectionRepository usersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
            return new UserConnectionRepositoryImpl(connectionFactoryLocator);
        }
    
        @Override
        @Bean
        public UserIdSource getUserIdSource() {
            return new UserIdSource() {
                @Override
                public String getUserId() {
                    User user = getUser();
                    if (user == null) {
                        throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
                    }
                    return user.getId();
                }
            };
        }
    
        @Bean
        public ReconnectFilter apiExceptionHandler(UsersConnectionRepository usersConnectionRepository, UserIdSource userIdSource) {
            return new ReconnectFilter(usersConnectionRepository, userIdSource);
        }
    
    
        @Bean
        @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
        public ConnectionRepository connectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
    
            User user = getUser();
            if (user == null) {
                throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
            }
            return usersConnectionRepository(connectionFactoryLocator).createConnectionRepository(user.getId());
        }
    
        @Bean
        @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
        public Facebook facebook(ConnectionRepository repository) {
            Connection<Facebook> connection = null;
    
            if (repository != null) {
               connection = repository.findPrimaryConnection(Facebook.class);
            }
    
            return connection != null ? connection.getApi() : null;
        }
    
    
    }