title: Spring Security OAuth 1.0 flow - Consumer verification
body: <p>I have an external partner that uses OAuth 1.0 to protect some resources. I need to access this resources and I would like to do this using Spring Boot and Spring Security OAuth. As I don't want to use XML configuration, I already searched for a way to set up everything via Java configuration. I found <a href="https://stackoverflow.com/questions/29001343/spring-boot-spring-oauth-java-configuration">this</a> thread that provided an example of how to do this. But serveral things regarding the OAuth 1.0 flow are not clear for me.</p>
  
  <p>My partner provides four endpoints for OAuth: an endpoint that provides a consumer token, a <code>request_token</code> endpoint, an authorization endpoint and an <code>access_token</code> endpoint. With my current setup (shown below) I can get a request token and the authorization endpoint gets called. However, the authorization endpoint does not ask for confirmation, but expects as URL parameters an email and a password and, after checking the credentials, returns the following:</p>
  
  <pre><code>oauth_verifier=a02ebdc5433242e2b6e582e17b84e313
  </code></pre>
  
  <p>And this is where the OAuth flow gets stuck.</p>
  
  <p>After reading some articles about OAuth 1.0 the usual flow is this:</p>
  
  <ol>
  <li>get consumer token / key</li>
  <li>get oauth token using the consumer token via <code>request_token</code> endpoint</li>
  <li>redirect to authorization URL and ask the user for confirmation</li>
  <li>redirect to consumer with verifier token</li>
  <li>user verifier token and oauth token to get access token via <code>access_token</code> endpoint</li>
  </ol>
  
  <p>First of all: steps 3 and 4 are not clear to me. I've found the <a href="https://github.com/spring-projects/spring-security-oauth/tree/master/samples/oauth" rel="nofollow noreferrer">Spring Security OAuth examples</a>, but it wasn't clear to me how, after confirming the access, the user / verifier token get send back to the consumer. Could someone please explain how this is done?</p>
  
  <p>Second: Given that my partners endpoint does not ask for confirmation but returns an oauth verifier right away, how can I use Spring Security OAuth with this setup? I was thinking about implementing my own authorization endpoint that calls the authorziation endpoint of my partner and then somehow makes the verifier known to my consumer, but I'm not sure how to do the latter part.</p>
  
  <p>Here is the code so far (with help for the thread mentioned above; the <code>ConsumerTokenDto</code> has been left out as it is trivial):</p>
  
  <p><strong>Application</strong></p>
  
  <pre class="lang-java prettyprint-override"><code>@SpringBootApplication
  public class Application {
  
      public static void main(String[] args) {
          SpringApplication.run(Application.class, args);
      }
  }
  </code></pre>
  
  <p><strong>Endpoint</strong></p>
  
  <pre class="lang-java prettyprint-override"><code>@RestController
  public class Endpoint {
      @Autowired
      private OAuthRestTemplate oAuthRestTemplate;
      private String url = "https://....";
  
      @RequestMapping("/public/v1/meters")
      public String getMeters() {
          try {
              return oAuthRestTemplate.getForObject(URI.create(url), String.class);
          } catch (Exception e) {
              LOG.error("Exception", e);
              return "";
          }
      }
  }
  </code></pre>
  
  <p><strong>OAuth configuration</strong></p>
  
  <pre class="lang-java prettyprint-override"><code>@Configuration
  @EnableWebSecurity
  public class OAuthConfig extends WebSecurityConfigurerAdapter {
  
      @Autowired
      private RestTemplateBuilder restTemplateBuilder;
      private ConsumerTokenDto consumerTokenDto;
  
      private static final String ID = "meters";
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.authorizeRequests().antMatchers("/**").permitAll();
          http.addFilterAfter(this.oauthConsumerContextFilter(), SwitchUserFilter.class);
          http.addFilterAfter(this.oauthConsumerProcessingFilter(), OAuthConsumerContextFilterImpl.class);
      }
  
      private OAuthConsumerContextFilter oauthConsumerContextFilter() {
          OAuthConsumerContextFilter filter = new OAuthConsumerContextFilter();
          filter.setConsumerSupport(this.consumerSupport());
          return filter;
      }
  
      private OAuthConsumerProcessingFilter oauthConsumerProcessingFilter() {
          OAuthConsumerProcessingFilter filter = new OAuthConsumerProcessingFilter();
          filter.setProtectedResourceDetailsService(this.prds());
  
          LinkedHashMap&lt;RequestMatcher, Collection&lt;ConfigAttribute&gt;&gt; map = new LinkedHashMap&lt;&gt;();
  
          // one entry per oauth:url element in xml
          map.put(
                  new AntPathRequestMatcher("/public/v1/**", null),
                  Collections.singletonList(new SecurityConfig(ID)));
  
          filter.setObjectDefinitionSource(new DefaultFilterInvocationSecurityMetadataSource(map));
  
          return filter;
      }
  
      @Bean
      OAuthConsumerSupport consumerSupport() {
          CoreOAuthConsumerSupport consumerSupport = new CoreOAuthConsumerSupport();
          consumerSupport.setProtectedResourceDetailsService(prds());
          return consumerSupport;
      }
  
      @Bean
      ProtectedResourceDetailsService prds() {
          InMemoryProtectedResourceDetailsService service = new InMemoryProtectedResourceDetailsService();
          Map&lt;String, ProtectedResourceDetails&gt; store = new HashMap&lt;&gt;();
          store.put(ID, prd());
          service.setResourceDetailsStore(store);
          return service;
      }
  
      ProtectedResourceDetails prd() {
          ConsumerTokenDto consumerToken = getConsumerToken();
          BaseProtectedResourceDetails resourceDetails = new BaseProtectedResourceDetails();
          resourceDetails.setId(ID);
          resourceDetails.setConsumerKey(consumerToken.getKey());
          resourceDetails.setSharedSecret(new SharedConsumerSecretImpl(consumerToken.getSecret()));
          resourceDetails.setRequestTokenURL("https://.../request_token");
          // the authorization URL does not prompt for confirmation but immediately returns an OAuth verifier
          resourceDetails.setUserAuthorizationURL(
                  "https://.../authorize?email=mail&amp;password=pw");
          resourceDetails.setAccessTokenURL("https://.../access_token");
          resourceDetails.setSignatureMethod(HMAC_SHA1SignatureMethod.SIGNATURE_NAME);
          return resourceDetails;
      }
  
      // get consumer token from provider
      private ConsumerTokenDto getConsumerToken() {
          if (consumerTokenDto == null) {
              MultiValueMap&lt;String, String&gt; body = new LinkedMultiValueMap&lt;&gt;();
              body.add("client", "Client");
  
              HttpHeaders headers = new HttpHeaders();
              headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
  
              HttpEntity&lt;MultiValueMap&lt;String, String&gt;&gt; request = new HttpEntity&lt;&gt;(body, headers);
  
              RestTemplate restTemplate = restTemplateBuilder.setConnectTimeout(1000).setReadTimeout(1000).build();
              restTemplate.getInterceptors().add(interceptor);
              restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
              ResponseEntity&lt;ConsumerTokenDto&gt; response = restTemplate
                      .exchange("https://.../consumer_token", HttpMethod.POST, request,
                              ConsumerTokenDto.class);
  
              consumerTokenDto = response.getBody();
          }
          return consumerTokenDto;
      }
  
      // create oauth rest template
      @Bean
      public OAuthRestTemplate oAuthRestTemplate() {
          OAuthRestTemplate oAuthRestTemplate = new OAuthRestTemplate(prd());
          oAuthRestTemplate.getInterceptors().add(interceptor);
          return oAuthRestTemplate;
      }
  }
  </code></pre>