Spring Security OAuth2 - Need clarification and help to configure Implicit flow
<p>I am struggling to configure Spring Security OAuth2 to support implicit flow (I had no problems with password or authorization code).</p>

<p>These are the different endpoints:</p>

<p><strong>Authorization server</strong> </p>

<pre><code>http://localhost:8082/oauth/authorize
http://localhost:8082/oauth/token
...
</code></pre>

<p><strong>Resource server</strong> </p>

<pre><code>http://localhost:8081/users (protected resource)
</code></pre>

<p><strong>Client</strong></p>

<p><code>http://localhost:8080/api/users</code> invokes <code>http://localhost:8081/users</code> initiating the OAuth2 dance.</p>

<p><strong>What I see is</strong>:</p>

<ol>
<li><p><code>http://localhost:8080/api/users</code> gets redirected to the authorization server with this in the URL: <code>http://localhost:8082/oauth/authorize?client_id=themostuntrustedclientid&amp;response_type=token&amp;redirect_uri=http://localhost:8080/api/accessTokenExtractor</code></p></li>
<li><p>I am prompted with the OAuth approval screen, where I grant all the scopes. Then the browser is redirected to the <code>redirect_uri</code>: <code>http://localhost:8080/api/accessTokenExtractor</code> <strong>with a fragment containing the access_token</strong>: <code>http://localhost:8080/api/accessTokenExtractor#access_token=3e614eca-4abe-49a3-bbba-1b8eea05c147&amp;token_type=bearer&amp;expires_in=55&amp;scope=read%20write</code></p></li>
</ol>

<p><strong>QUESTIONS:</strong></p>

<p><strong>a. HOW CAN I RESUME AUTOMATICALLY THE EXECUTION OF THE ORIGINAL REQUEST?</strong></p>

<p>The spec defines this behaviour with the access_token as a fragment in the URL:  since the fragments aren't sent directly to the servers, we have to use a web page script to extract it and send it to the client (my spring-mvc application). This implies setting a <code>redirect_uri</code> pointing at the script, instead of to the original request:</p>

<p><code>http://localhost:8080/api/accessTokenExtractor#access_token=3e614eca-4abe-49a3-bbba-1b8eea05c147&amp;token_type=bearer&amp;expires_in=55&amp;scope=read%20write</code></p>

<p>The accessTokenExtractor web page sends the token to the client. The problem is I don't have the original call (<a href="http://localhost:8080/api/users" rel="nofollow noreferrer">http://localhost:8080/api/users</a>) anymore...</p>

<p>b. Below you can see the client invocation:</p>

<pre><code>    restTemplate.getOAuth2ClientContext().getAccessTokenRequest()
        .setAll(['client_id': 'themostuntrustedclientid',
                 'response_type': 'token', 
                 'redirect_uri': 'http://localhost:8080/api/accessTokenExtractor'])

    HttpHeaders headers = new HttpHeaders()
    ResponseEntity&lt;List&lt;String&gt;&gt; response = restTemplate.exchange('http://localhost:8081/users', HttpMethod.GET, null, new ParameterizedTypeReference&lt;List&lt;String&gt;&gt;(){}, [])
    response.getBody()
</code></pre>

<p>if I don't set manually the parameters client_id, response_type and redirect_uri  (necessary for the <code>UserRedirectRequiredException</code>) the authorization server complains, it needs them. <strong>ARE WE EXPECTED TO SET THEM MANUALLY?</strong> </p>

<p>The strange thing is that they are available in <code>ImplicitAccessorProvider.obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)</code>:</p>

<pre><code>ImplicitResourceDetails resource = (ImplicitResourceDetails) details;
    try {
        ...
</code></pre>

<p><code>resource</code> contains all of them, however they are not copied to request.</p>

<p>If we compare with <code>AuthorizationCodeAccessTokenProvider</code> here the private method <code>getRedirectForAuthorization()</code> does it automatically...<strong>WHY THE DIFFERENCE?</strong></p>

<p><strong>CONFIGURATION:</strong></p>

<p><strong>Authorization Server config</strong>:</p>

<pre><code>@EnableAuthorizationServer
@SpringBootApplication
class Oauth2AuthorizationServerApplication {

    static void main(String[] args) {
        SpringApplication.run Oauth2AuthorizationServerApplication, args
    }
}

@Configuration
class OAuth2Config extends AuthorizationServerConfigurerAdapter{

    @Autowired
    private AuthenticationManager authenticationManager

    @Bean
    public UserDetailsService userDetailsService() throws Exception {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager([])
        manager.createUser(new User("jose","mypassword", [new SimpleGrantedAuthority("ROLE_USER")]))
        manager.createUser(new User("themostuntrustedclientid","themostuntrustedclientsecret", [new SimpleGrantedAuthority("ROLE_USER")]))
        return manager
    }

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()

        //curl trustedclient:trustedclientsecret@localhost:8082/oauth/token -d grant_type=password -d username=user -d password=cec31d99-e5ee-4f1d-b9a3-8d16d0c6eeb5 -d scope=read
        .withClient("themostuntrustedclientid")
            .secret("themostuntrustedclientsecret")
            .authorizedGrantTypes("implicit")
            .authorities("ROLE_USER")
            .scopes("read", "write")
            .accessTokenValiditySeconds(60)

    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(this.authenticationManager);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //security.checkTokenAccess('hasRole("ROLE_RESOURCE_PROVIDER")')
        security.checkTokenAccess('isAuthenticated()')
    }
}
</code></pre>

<p><strong>resource server config</strong> and protected endpoint:</p>

<pre><code>@EnableResourceServer
@SpringBootApplication
class Oauth2ResourceServerApplication {

    static void main(String[] args) {
        SpringApplication.run Oauth2ResourceServerApplication, args
    }
}

@Configuration
class OAuth2Config extends ResourceServerConfigurerAdapter{

    @Value('${security.oauth2.resource.token-info-uri}')
    private String checkTokenEndpointUrl

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            // Since we want the protected resources to be accessible in the UI as well we need
            // session creation to be allowed (it's disabled by default in 2.0.6)
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
        .and()
            .requestMatchers().antMatchers("/users/**")
        .and()
            .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/users").access("#oauth2.hasScope('read')")
                .antMatchers(HttpMethod.PUT, "/users/**").access("#oauth2.hasScope('write')")
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices()
        remoteTokenServices.setCheckTokenEndpointUrl(checkTokenEndpointUrl)
        remoteTokenServices.setClientId("usersResourceProvider")
        remoteTokenServices.setClientSecret("usersResourceProviderSecret")
        resources.tokenServices(remoteTokenServices)
    }
}

@RestController
class UsersRestController {

    private Set&lt;String&gt; users = ["jose", "ana"]

    @GetMapping("/users")
    def getUser(){
        return users
    }

    @PutMapping("/users/{user}")
    void postUser(@PathVariable String user){
        users.add(user)
    }

}
</code></pre>

<p>And this is the <strong>client config</strong>:</p>

<pre><code>@EnableOAuth2Client
@SpringBootApplication
class SpringBootOauth2ClientApplication {

    static void main(String[] args) {
        SpringApplication.run SpringBootOauth2ClientApplication, args
    }
}

@Configuration
class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.eraseCredentials(false)
            .inMemoryAuthentication().withUser("jose").password("mypassword").roles('USER')
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
        .authorizeRequests()
        .anyRequest().hasRole('USER')
        .and()
        .formLogin()
    }

}

@Configuration
class OAuth2Config {

    @Value('${oauth.resource:http://localhost:8082}')
    private String baseUrl

    @Value('${oauth.authorize:http://localhost:8082/oauth/authorize}')
    private String authorizeUrl

    @Value('${oauth.token:http://localhost:8082/oauth/token}')
    private String tokenUrl

    @Autowired
    private OAuth2ClientContext oauth2Context

    @Bean
    OAuth2ProtectedResourceDetails resource() {
        ImplicitResourceDetails resource = new ImplicitResourceDetails()
        resource.setAuthenticationScheme(AuthenticationScheme.header)
        resource.setAccessTokenUri(authorizeUrl)
        resource.setUserAuthorizationUri(authorizeUrl);
        resource.setClientId("themostuntrustedclientid")
        resource.setClientSecret("themostuntrustedclientsecret")
        resource.setScope(['read', 'write'])
        resource
    }

    @Bean
    OAuth2RestTemplate restTemplate() {
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource(), oauth2Context)
        //restTemplate.setAuthenticator(new ApiConnectOAuth2RequestAuthenticator())
        restTemplate
    }
}
</code></pre>

<p>My <strong>client</strong> has the following <strong>controller</strong> that invokes a protected aouth2 endpoint from the resource server:</p>

<pre><code>@RestController
class ClientRestController {

    @Autowired
    private OAuth2RestTemplate restTemplate

    def exceptionHandler(InsufficientScopeException ex){
        ex
    }

    @GetMapping("/home")
    def getHome(HttpSession session){
        session.getId()
    }

    @GetMapping("/users")
    def getUsers(HttpSession session){
        println 'Session id: '+ session.getId()

        //TODO Move to after authentication
        Authentication auth = SecurityContextHolder.getContext().getAuthentication()
        restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setAll(['client_id': 'themostuntrustedclientid', 'response_type': 'token', 'redirect_uri': 'http://localhost:8080/api/users'])

        HttpHeaders headers = new HttpHeaders()
        ResponseEntity&lt;List&lt;String&gt;&gt; response = restTemplate.exchange('http://localhost:8081/users', HttpMethod.GET, null, new ParameterizedTypeReference&lt;List&lt;String&gt;&gt;(){}, [])


        response.getBody()
    }
}
</code></pre>