Add optional Google Sign In in my Spring Boot + Security + web Application - spring

I am working on a Spring boot web application. I have now working a registration and login system using Spring Security with a custom userDetailService.
Now I want add a register-login system using Google Accounts. I created my Google API keys and added them to the application.properties. I think is not necessary use .yml propertie files here:
# ===============================
# = OAUTH2
# ===============================
security.oauth2.client.client-id=clientId Here
security.oauth2.client.client-secret=clientSecret here
security.oauth2.client.access-token-uri=https://www.googleapis.com/oauth2/v3/token
security.oauth2.client.user-authorization-uri=https://accounts.google.com/o/oauth2/auth
security.oauth2.client.token-name=oauth_token
security.oauth2.client.authentication-scheme=query
security.oauth2.client.client-authentication-scheme=form
security.oauth2.client.scope=profile
security.oauth2.resource.user-info-uri=https://www.googleapis.com/userinfo/v2/me
security.oauth2.resource.prefer-token-info=false
I added OAuth2 support to my Spring Boot application on this way:
#SpringBootApplication
#EnableOAuth2Sso
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
Now I want keep the posibility to login using Google or login using a website account, but I only found manuals about unique login or multiple providers login (Facebook, Google, Twitter..)
In my SpringSecurity configuration class I have this. I think that I have to create a authenticationProvider for Google and link it to the google access url in my app, but I am so confused yet about this:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
/**
* Obtenemos información de persistencia
*/
// #formatter:off
auth
//.authenticationProvider(googleOauth2AuthProvider())
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder);
// #formatter:on
}
...
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] anonymousRequest = { urls};
http
.authorizeRequests()
//..other rules

You have to use a composite filter in which you configure your desired authentication providers, for example:
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(facebook(), "/login/facebook"));
filters.add(ssoFilter(google(), "/login/google"));
filter.setFilters(filters);
return filter;
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter(
path);
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(),
client.getClient().getClientId());
tokenServices.setRestTemplate(oAuth2RestTemplate);
oAuth2ClientAuthenticationFilter.setTokenServices(tokenServices);
return oAuth2ClientAuthenticationFilter;
}
where:
#Bean
#ConfigurationProperties("google")
public ClientResources google() {
return new ClientResources();
}
#Bean
#ConfigurationProperties("facebook")
public ClientResources facebook() {
return new ClientResources();
}
and:
class ClientResources {
#NestedConfigurationProperty
private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();
#NestedConfigurationProperty
private ResourceServerProperties resource = new ResourceServerProperties();
public AuthorizationCodeResourceDetails getClient() {
return client;
}
public ResourceServerProperties getResource() {
return resource;
}
}
finally, add the filter before the BasicAuthenticationFilter in your HTTP security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] anonymousRequest = { urls};
http
.authorizeRequests()
//..other rules
addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
Ps: your configuration properties has to start with the value specified in the #ConfigurationProperties("facebook"):
facebook:
client:
clientId: yourCliendId
clientSecret: yourClientSecret
accessTokenUri: https://graph.facebook.com/oauth/access_token
userAuthorizationUri: https://www.facebook.com/dialog/oauth
tokenName: oauth_token
authenticationScheme: query
registeredRedirectUri: http://localhost:8083/app.html
preEstablishedRedirectUri: http://localhost:8083/app.html
clientAuthenticationScheme: form
resource:
userInfoUri: https://graph.facebook.com/me
This is inspired from the example presented here: https://github.com/spring-guides/tut-spring-boot-oauth2/tree/master/github

You can achieve this using Spring Social or OAUTH2
If you want to do using spring social be aware that Google is not supported by default in spring boot social so you have to do a couple of extra steps.
Add Maven Dependencies
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-google</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
Add a GoogleAutoConfiguration Class
Do Ctrl+Shift+T in your IDE(eclipse) and look for FacebookAutoConfiguration class you should be able to find it either in org.springframework.boot.autoconfigure.social package in spring-autoconfigure.jar. Copy this File and replace Facebook with Google.
3.Add GoogleProperties
In the same package add the below class
#ConfigurationProperties(prefix = "spring.social.google")
public class GoogleProperties extends SocialProperties{
Update the application.properties with your google API key
Follow this link for complete description and step by step instruction
Hope It helps !!
If you want to do using OAUTH2 here is a working example

Related

Get Keycloak AccessToken in controller

I am trying to get the access token after a successfully login, and after a lot of researched I got to this post, how to get Keycloak access token and store it in db for spring boot?, where it's said to make a Keycloak login manually, but I don't know how. The link to the document in the comments doesn't work anymore.
I also tired to get it thought the headers, but no Authorization header is sent.
String authHeader = servletRequest.getHeader("Authorization"); //returns null
if (authHeader != null
&& !authHeader.isEmpty()
&& authHeader.startsWith("Bearer")) {
String accessToken = authHeader.substring("Bearer".length()).trim();
if (accessToken != null) {
return new ResponseEntity(true, HttpStatus.OK);
} else {
return new ResponseEntity(false, HttpStatus.UNAUTHORIZED);
}
} else {
log.error("Invalid authorization header. ");
return new ResponseEntity(HttpStatus.BAD_REQUEST);
}
I tried also to get it throught the Principal, but I get an error:
java.lang.ClassCastException: class org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken cannot be cast to class org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
.currentRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
KeycloakAuthenticationToken userPrincipal = (KeycloakAuthenticationToken) request.getUserPrincipal();
SimpleKeycloakAccount userPrincipalDetails = (SimpleKeycloakAccount) userPrincipal.getDetails();
return userPrincipalDetails
.getKeycloakSecurityContext()
.getToken();
The same error is displayed if I try:
KeycloakAuthenticationToken authenticatication = (KeycloakAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
I can login/logout, but I cannot get the accessToken...
#KeycloakConfiguration
#EnableWebSecurity
#Order(1)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
private final KeycloakLogoutHandler keycloakLogoutHandler;
public SecurityConfig(KeycloakLogoutHandler keycloakLogoutHandler) {
this.keycloakLogoutHandler = keycloakLogoutHandler;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/somepage/*").permitAll()
.anyRequest().authenticated();
http.oauth2Login()
.and()
.logout()
.addLogoutHandler(keycloakLogoutHandler)
.logoutSuccessUrl("/");
}
}
Any ideas?
First, do not use Keycloak libs for Spring: it is (very) deprecated. Instead use:
spring-boot-starter-oauth2-resource-server if your app is a REST API. Instruction in the first of this series of tutorials.
spring-boot-starter-oauth2-client if your app serves UI (with thymeleaf or whatever)
The exact type of Authentication returned by SecurityContextHolder.getContext().getAuthentication() depends on your app being a client or a resource-server and it being configured with JWT decoder or token introspection, but all expose the Bearer access-token string. Just get it from there.
In the case your app is a resource-server (REST API), you might use one of the spring-boot starters I maintain for spring-boot-starter-oauth2-resource-server auto-configuration from properties. This quite simplifies the configuration compared to the first tutorial linked before:
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<!-- replace "webmvc" with "weblux" if your app is reactive -->
<!-- replace "jwt" with "introspecting" to use token introspection instead of JWT decoding -->
<artifactId>spring-addons-webmvc-jwt-resource-server</artifactId>
<!-- this version is to be used with spring-boot 3.0.0-RC1, use 5.x for spring-boot 2.6.x or before -->
<version>6.0.4</version>
</dependency>
#EnableMethodSecurity
public static class WebSecurityConfig { }
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/master
com.c4-soft.springaddons.security.issuers[0].authorities.claims=realm_access.roles,ressource_access.some-client.roles
com.c4-soft.springaddons.security.cors[0].path=/some-api
The Authentication for authorized requests will the be JwtAuthenticationToken:
#RestController
#RequestMapping("/demo")
public class DemoController {
#GetMapping("/access-token")
#PreAuthorize("isAuthenticated()")
public String getAccessToken(JwtAuthenticationToken auth) {
return auth.getToken().getTokenValue();
}
}
Disclaimer: be carefull with what you do with access-tokens and who you expose it to. If it leaks, it might be used for identity usurpation.

Spring Security with OAuth2(Keycloak) disable default login page

I have successfully configured Spring Boot Spring Security with Keycloak. Everything works fine. In order to login, I use the following URL: http://localhost:8081/realms/MY_REALM_NAME
But when I try to access the following page: http://localhost:8080/login I see the following page:
I'd like to disable/remove this page. How to properly configure it with Spring Security?
UPDATED
My SpringSecurity configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends VaadinWebSecurityConfigurerAdapter {
private final ClientRegistrationRepository clientRegistrationRepository;
private final GrantedAuthoritiesMapper authoritiesMapper;
private final ProfileService profileService;
SecurityConfiguration(ClientRegistrationRepository clientRegistrationRepository,
GrantedAuthoritiesMapper authoritiesMapper, ProfileService profileService) {
this.clientRegistrationRepository = clientRegistrationRepository;
this.authoritiesMapper = authoritiesMapper;
this.profileService = profileService;
SecurityContextHolder.setStrategyName(VaadinAwareSecurityContextHolderStrategy.class.getName());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
// Enable OAuth2 login
.oauth2Login(oauth2Login ->
oauth2Login
.clientRegistrationRepository(clientRegistrationRepository)
.userInfoEndpoint(userInfoEndpoint ->
userInfoEndpoint
// Use a custom authorities mapper to get the roles from the identity provider into the Authentication token
.userAuthoritiesMapper(authoritiesMapper)
)
// Use a Vaadin aware authentication success handler
.successHandler(new KeycloakVaadinAuthenticationSuccessHandler(profileService))
)
// Configure logout
.logout(logout ->
logout
// Enable OIDC logout (requires that we use the 'openid' scope when authenticating)
.logoutSuccessHandler(logoutSuccessHandler())
// When CSRF is enabled, the logout URL normally requires a POST request with the CSRF
// token attached. This makes it difficult to perform a logout from within a Vaadin
// application (since Vaadin uses its own CSRF tokens). By changing the logout endpoint
// to accept GET requests, we can redirect to the logout URL from within Vaadin.
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
);
}
#Bean
#Primary
public SpringViewAccessChecker springViewAccessChecker(AccessAnnotationChecker accessAnnotationChecker) {
return new KeycloakSpringViewAccessChecker(accessAnnotationChecker, "/oauth2/authorization/keycloak");
}
private OidcClientInitiatedLogoutSuccessHandler logoutSuccessHandler() {
var logoutSuccessHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository);
logoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
return logoutSuccessHandler;
}
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
// Don't apply security rules on our static pages
web.ignoring().antMatchers("/session-expired");
}
#Bean
public PolicyFactory htmlSanitizer() {
// This is the policy we will be using to sanitize HTML input
return Sanitizers.FORMATTING.and(Sanitizers.BLOCKS).and(Sanitizers.STYLES).and(Sanitizers.LINKS);
}
}
Have tried formLogin().disable() method?
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
//your config here
.and().formLogin().disable();
}

How can I do to my spring boot resource server oauth 2 get user's extra data from api when user authenticate e keep it into security context?

I have a resource server done with Spring Boot. I'm using Spring Security 5.3 to authenticate and authorize the frontend exchange data. I've configured a authorization server "issuer-uri" in application.yml that provides and validates the access_token (jwt).
Until there ok. The problem that authorization server doesn't provide at once every user's information that I need in access_token or id_token. With the sub claim and access_token I need to do a request to endpoint to get more extra data about user.
I would like to know how can I do a request to get that information just when the user authenticates and put them into security context togheter the information that's already comes. So that way, I could get that information in some service when needed without make a request to endpoint each time:
SecurityContextHolder.getContext().getAuthentication().getDetails()
It's here my WebSecurityConfigurerAdapter
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String CLAIM_ROLES = "role";
private static final String AUTHORITY_PREFIX = "ROLE_";
#Value("${sso.issuers_uri}")
private String issuers;
Map<String, AuthenticationManager> authenticationManagers = new HashMap<>();
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver =
new JwtIssuerAuthenticationManagerResolver(authenticationManagers::get);
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] result = issuers.split(",");
List<String> arrIssuers = Arrays.asList(result);
arrIssuers.stream().forEach(issuer -> addManager(authenticationManagers, issuer));
http
.httpBasic().disable()
.formLogin(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.authorizeRequests(auth -> auth
.antMatchers(
"/*",
"/signin-oidc",
"/uri-login_unico",
"/assets/**","/views/**",
"index.html",
"/api/segmentos/listar_publicados",
"/api/modelos",
"/api/modelos/*"
).permitAll()
.antMatchers(
"/api/admin/**"
).hasRole("role.PGR.Admin")
.antMatchers(
"/api/govbr/**"
).hasAnyAuthority("SCOPE_govbr_empresa")
.anyRequest().authenticated()
).oauth2ResourceServer(oauth2ResourceServer -> {
oauth2ResourceServer.authenticationManagerResolver(this.authenticationManagerResolver);
});
}
public void addManager(Map<String, AuthenticationManager> authenticationManagers, String issuer) {
JwtAuthenticationProvider authenticationProvider = new JwtAuthenticationProvider(JwtDecoders.fromOidcIssuerLocation(issuer));
authenticationProvider.setJwtAuthenticationConverter(getJwtAuthenticationConverter());
authenticationManagers.put(issuer, authenticationProvider::authenticate);
}
private Converter<Jwt, AbstractAuthenticationToken> getJwtAuthenticationConverter() {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(getJwtGrantedAuthoritiesConverter());
return jwtAuthenticationConverter;
}
private Converter<Jwt, Collection<GrantedAuthority>> getJwtGrantedAuthoritiesConverter() {
JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();
converter.setAuthorityPrefix(AUTHORITY_PREFIX);
converter.setAuthoritiesClaimName(CLAIM_ROLES);
return converter;
}
}
I don't know if I need to do a custom AuthenticationManger or if I can do this with a security filter after authenticated. If someone could help me, I really apprecite it. Tks!!!

Storing JWT tokens on OAuth2 web client using Spring Security

I'm implementing an OAuth2 web application Client using Spring Boot 2.1.3 and Spring Security 5.1.3 that is obtaining JWT tokens from an authorization server through authorization code grant type and calls a protected resource server.
This is how the implementation looks up till now:
Security configuration and a restTemplate bean used to call the protected resource:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.and()
.oauth2Client()
.and().logout().logoutSuccessUrl("/");
}
#Bean
public RestTemplate restTemplate(OAuth2AuthorizedClientService clientService) {
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new AuthorizationHeaderInterceptor(clientService));
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
The interceptor that adds the authorization header (from the framework's InMemoryOAuth2AuthorizedClientService) in the restTemplate:
public class AuthorizationHeaderInterceptor implements ClientHttpRequestInterceptor {
private OAuth2AuthorizedClientService clientService;
public AuthorizationHeaderInterceptor(OAuth2AuthorizedClientService clientService) {
this.clientService = clientService;
}
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String accessToken = null;
if (authentication != null && authentication.getClass().isAssignableFrom(OAuth2AuthenticationToken.class)) {
OAuth2AuthenticationToken auth = (OAuth2AuthenticationToken) authentication;
String clientRegistrationId = auth.getAuthorizedClientRegistrationId();
OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(clientRegistrationId, auth.getName());
accessToken = client.getAccessToken().getTokenValue();
request.getHeaders().add("Authorization", "Bearer " + accessToken);
}
return execution.execute(request, bytes);
}
}
And the controller that calls the protected resource server:
#Controller
#RequestMapping("/profile")
public class ProfileController {
#Autowired
private RestTemplate restTemplate;
#Value("${oauth.resourceServerBase}")
private String resourceServerBase;
#GetMapping
public String getProfile(Model model) {
Profile profile = restTemplate.getForEntity(resourceServerBase + "/api/profile/", Profile.class).getBody();
model.addAttribute("profile", profile);
return "profile";
}
}
The OAuth2 client configuration is directly in the application.yml:
spring:
security:
oauth2:
client:
registration:
auth-server:
client-id: webClient
client-secret: clientSecret
scope: read,write
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8081/client/login/oauth2/code/auth-server
provider:
auth-server:
authorization-uri: http://localhost:8080/auth-server/oauth/authorize
token-uri: http://localhost:8080/auth-server/oauth/token
user-info-uri: http://localhost:8082/resource-server/users/info
user-name-attribute: user_name
After doing some debugging I've observed that at the end of a successful authentication flow through OAuth2LoginAuthtenticationFilter the framework is storing the obtained access and refresh JWT tokens under OAuth2AuthorizedClient model in memory through the provided InMemoryOAuth2AuthorizedClientService.
I am trying to find out how to override this behaviour so that the tokens can remain available after a server restart. And also keep the user logged in based on this.
Should I just provide a custom OAuth2AuthorizedClientService implementation? How could I configure Spring Security to use it? And should this custom implementation store the tokens in a cookie?
Should I just provide a custom OAuth2AuthorizedClientService
implementation?
I think yes, for solving your use case
How could I configure Spring Security to use it?
From spring doc:
If you would like to provide a custom implementation of
AuthorizationRequestRepository that stores the attributes of
OAuth2AuthorizationRequest in a Cookie, you may configure it as shown
in the following example:
#EnableWebSecurity
public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Client()
.authorizationCodeGrant()
.authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
...
}
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() {
return new HttpCookieOAuth2AuthorizationRequestRepository();
}
}

How to change response_type on Spring OAuth2

This is my configuration for OAuth2 login with Instagram
instagram:
client:
clientId: clientId
clientSecret: clientSeret
accessTokenUri: https://api.instagram.com/oauth/access_token
userAuthorizationUri: https://api.instagram.com/oauth/authorize
clientAuthenticationScheme: form
scope:
- basic
- public_content
resource:
userInfoUri: https://api.instagram.com/v1/users/self/
delimiter: +
This is the request made by Spring:
https://api.instagram.com/oauth/authorize?client_id=clientId&redirect_uri=http://localhost:8080/login/instagram&response_type=code&state=CG6mMQ
How can I change the response_type to &response_type=token and how can I why isn't Spring adding the scopes?
Here is the App class:
#SpringBootApplication
#EnableOAuth2Client
public class App extends WebSecurityConfigurerAdapter {
#Autowired
OAuth2ClientContext oauth2ClientContext;
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**", "/webjars/**")
.permitAll()
.anyRequest()
.authenticated().and().exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/"))
// logout
.and().logout().logoutSuccessUrl("/").permitAll()
// CSRF
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// filters
.and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
}
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
// facebook ...
// google ...
// instagram
OAuth2ClientAuthenticationProcessingFilter instagramFilter =
new OAuth2ClientAuthenticationProcessingFilter("/login/instagram");
OAuth2RestTemplate instagramTemplate =
new OAuth2RestTemplate(instagram(), oauth2ClientContext);
instagramFilter.setRestTemplate(instagramTemplate);
instagramFilter.setTokenServices(
new UserInfoTokenServices(instagramResource().getUserInfoUri(), instagram().getClientId()));
filters.add(instagramFilter);
filter.setFilters(filters);
return filter;
}
#Bean
#ConfigurationProperties("instagram.client")
public AuthorizationCodeResourceDetails instagram() {
return new AuthorizationCodeResourceDetails();
}
#Bean
#ConfigurationProperties("instagram.resource")
public ResourceServerProperties instagramResource() {
return new ResourceServerProperties();
}
#Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(
OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
}
How can I change the response_type to &response_type=token
As I read the code, AuthorizationCodeAccessTokenProvider‘s response_type is hard code.
private UserRedirectRequiredException getRedirectForAuthorization(AuthorizationCodeResourceDetails resource,
AccessTokenRequest request) {
// we don't have an authorization code yet. So first get that.
TreeMap<String, String> requestParameters = new TreeMap<String, String>();
requestParameters.put("response_type", "code"); // oauth2 spec, section 3
So, If you want to change the response_code, you can extend the AuthorizationCodeAccessTokenProvider, or implements the AccessTokenProvider, and then inject to the OAuth2RestTemplate accessTokenProvider(the default value is a AccessTokenProviderChain that contains AuthorizationCodeAccessTokenProvider, ResourceOwnerPasswordAccessTokenProvider and so on, use your own provider instead of AuthorizationCodeAccessTokenProvider).
Or you can change the redirectStrategy in OAuth2ClientContextFilter, and change the request param when redirect, but I don't recommend this.
How can I why isn't Spring adding the scopes?
AuthorizationCodeAccessTokenProvider will get scopes from AuthorizationCodeResourceDetails, and add them to UserRedirectRequiredException. I think the scope can't be injected to AuthorizationCodeResourceDetails, because the scope is not under the client. Maybe you need to change to this.
instagram:
client:
clientId: clientId
clientSecret: clientSeret
accessTokenUri: https://api.instagram.com/oauth/access_token
userAuthorizationUri: https://api.instagram.com/oauth/authorize
clientAuthenticationScheme: form
scope:
- basic
- public_content
You can access the query parameters from the UserRedirectRequiredException. So in the code which throws the exception and thus causes the redirect to happen, e.g. in your filter, you can do something like:
try {
accessToken = restTemplate.getAccessToken();
}
catch (UserRedirectRequiredException e) {
Map<String, String> requestParams = e.getRequestParams();
requestParams.put("response_type", "token");
throw e; //don't forget to rethrow
}
You can only replace values this way. If you needed to add a parameter value alongside an existing value, you'd need to use a delimiter such as '+'. There is no standard way of adding multiple parameter values and would depend on what the owner of the API accepts. Some APIs may not accept delimeters at all.

Resources