Simplify Configuring Log In using Twitter / X v2 APIs
It is not as simple as I would expect to authenticate using Twitter / X v2 Log In APIs. We should simplify this process. This is inspired by the question at https://devcommunity.x.com/t/oauth2-in-spring-boot-3-implementation/233316
- [ ] #16377
- [x] #16379
- [x] #16380
- [x] #16382
- [x] #16383
- [ ] #16390
- [ ] #16391
NOTE: I added this here instead of https://devcommunity.x.com/t/oauth2-in-spring-boot-3-implementation/233316 because X was rejecting my POST due to the links in it. I spent too long trying to figure out what was wrong, so I'm posting it here instead.
Let's go over the changes:
- X uses PKCE but also requires the client id / secret to be provided as basic authentication. This means that client-authentication-method=none is incorrect. You can change the value to
client_secret_basicor remove the property since this is the default. Unfortunately, there is not currently a declarative way to use PKCE + Basic authentication in Spring Security. Instead, you will need to add some code:
@Bean
SecurityFilterChain springSecurity(HttpSecurity http, OAuth2AuthorizationRequestResolver resolver) throws Exception {
http
.authorizeHttpRequests( r -> r
.anyRequest().authenticated()
)
.oauth2Login(l -> l
.authorizationEndpoint(a -> a
.authorizationRequestResolver(resolver)
)
);
return http.build();
}
@Bean
OAuth2AuthorizationRequestResolver pkceResolver(ClientRegistrationRepository clientRegistrationRepository) {
DefaultOAuth2AuthorizationRequestResolver resolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository,"/oauth2/authorization");
resolver.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce());
return resolver;
}
This should be improved when gh-16382 is resolved.
-
In the sample you provided, it has the scope of
users.read, but X's/users/meendpoint requires both theusers.readandtweet.readscopes. -
The
redirect-uriis required and the value provided in the sample is correct. However, it can be improved to work with any registration id by changing the value to{baseUrl}/login/oauth2/code/{registrationId}. This should be defaulted so the property can be omitted and will be fixed in gh-16377. -
The
user-name-attribute=nameis incorrect. Twitterdata.usernameto represent the username. This can be fixed by using the following:
@Bean
DefaultOAuth2UserService userService() {
DefaultOAuth2UserService service = new DefaultOAuth2UserService();
// unwrap the response from the user to be the contents of the `data` JSON propert
service.setAttributesConverter((
request) -> (attributes) -> (java.util.Map<String, Object>) attributes.get("data"));
return service;
}
# Since the code above unwrapped the attributes, we can now access the username from the username attribute
spring.security.oauth2.client.provider.x.user-name-attribute=username
We plan to improve this with gh-16390.