title: Mapping user roles to oauth2 scopes/authorities
body: <p>We have a entitlements database which has application id, roles  and users mapped to roles per application. Following the <a href="https://stackoverflow.com/questions/22417780/using-scopes-as-roles-in-spring-security-oauth2-provider">advice on thread</a> how do I map user roles to oauth2 scopes/authorities based on resourceId?</p>
  <p>Ignoring the entitlements database I mentioned above do I map roles &quot;USER&quot;, &quot;READER&quot;, &quot;WRITER&quot; to oauth2 scopes/authorities <strong>based on user and resourceId</strong> in below code?</p>
  <p><strong>User Authentication/Authorization Config</strong></p>
  <pre class="lang-java prettyprint-override"><code>    @Configuration
      @Order(-10)
      protected static class LoginConfig extends WebSecurityConfigurerAdapter {
      
          ....
      
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              // auth.parentAuthenticationManager(authenticationManager);
              // @formatter:off
              auth.inMemoryAuthentication()
                  .withUser(&quot;admin&quot;).password(&quot;admin&quot;)
                      .roles(&quot;ADMIN&quot;, &quot;USER&quot;, &quot;READER&quot;, &quot;WRITER&quot;)
                  .and()
                  .withUser(&quot;user&quot;).password(&quot;password&quot;)
                      .roles(&quot;USER&quot;)
                  .and()
                  .withUser(&quot;audit&quot;).password(&quot;audit&quot;)
                      .roles(&quot;USER&quot;, &quot;ADMIN&quot;, &quot;READER&quot;);
              // @formatter:on
          }
      }
  </code></pre>
  <p><strong>OAuth2 Config</strong></p>
  <pre class="lang-java prettyprint-override"><code>    @Configuration
      @EnableAuthorizationServer
      protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
      
          @Autowired
          private AuthenticationManager authenticationManager;
      
          @Override
          public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
              // @formatter:off
              clients.inMemory()
                  .withClient(&quot;acme&quot;).secret(&quot;acmesecret&quot;)
                      .authorizedGrantTypes(&quot;authorization_code&quot;, &quot;refresh_token&quot;, &quot;password&quot;)
                      .scopes(&quot;openid&quot;)
                  .and()
                  .withClient(&quot;trusted&quot;).secret(&quot;shuush&quot;)
                      .authorizedGrantTypes(&quot;client_credentials&quot;)
                      .scopes(&quot;openid&quot;);
              // @formatter:on
          }
      
          @Override
          public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
              endpoints.authenticationManager(authenticationManager);
          }
      
          @Override
          public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
              oauthServer.checkTokenAccess(&quot;isAuthenticated()&quot;);
          }
      }
  </code></pre>
  <p><strong>Update 1:</strong></p>
  <p>Introduced a custom <a href="https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/OAuth2RequestFactory.java" rel="nofollow noreferrer">OAuth2RequestFactory</a> into the config to set checkUserScopes to true. While this setup works for &quot;client_credentails&quot;, it fails for &quot;code&quot; grants. For &quot;code&quot; grants, <a href="https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/request/DefaultOAuth2RequestFactory.java" rel="nofollow noreferrer">DefaultOAuth2RequestFactory</a> tries to <a href="https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/request/DefaultOAuth2RequestFactory.java#L147" rel="nofollow noreferrer">maps authorities</a> for client (acme) rather than user during the authorization step.
  Other thought is to implement <a href="https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/ClientDetailsService.java" rel="nofollow noreferrer">ClientDetailsService</a> that add authorities of client (acme) based on the logged-in user (admin/user) but not sure on how to grab logged-in user from SecurityContext since it is overwritten with client (acme) during authorization step. Any ideas?</p>
  <pre class="lang-java prettyprint-override"><code>    public class ScopeMappingOAuth2RequestFactory extends DefaultOAuth2RequestFactory {
      
          private SecurityContextAccessor securityContextAccessor = new DefaultSecurityContextAccessor();
      
          public ScopeMappingOAuth2RequestFactory(ClientDetailsService clientDetailsService) {
              super(clientDetailsService);
              super.setCheckUserScopes(true);
          }
      
          /**
           * @param securityContextAccessor the security context accessor to set
           */
          @Override
          public void setSecurityContextAccessor(SecurityContextAccessor securityContextAccessor) {
              this.securityContextAccessor = securityContextAccessor;
              super.setSecurityContextAccessor(securityContextAccessor);
          }
      
          @Override
          public AuthorizationRequest createAuthorizationRequest(Map&lt;String, String&gt; authorizationParameters) {
              AuthorizationRequest request = super.createAuthorizationRequest(authorizationParameters);
      
              if (securityContextAccessor.isUser()) {
                  request.setAuthorities(securityContextAccessor.getAuthorities());
              }
      
              return request;
          }
      
      }
  </code></pre>
  <p>and updated related code to</p>
  <pre class="lang-java prettyprint-override"><code>    @EnableAuthorizationServer
      protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
      
          @Autowired
          private AuthenticationManager authenticationManager;
      
          private InMemoryClientDetailsService clientDetailsService;
      
          private Map&lt;String, ClientDetails&gt; clientDetailsStore;
      
          public InMemoryClientDetailsService clientDetailsService() {
              if (clientDetailsService == null) {
                  clientDetailsStore = new HashMap&lt;String, ClientDetails&gt;();
                  InMemoryClientDetailsService m = new InMemoryClientDetailsService() {
      
                      @Override
                      public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
                          ClientDetails details = clientDetailsStore.get(clientId);
                          if (details == null) {
                              throw new NoSuchClientException(&quot;No client with requested id: &quot; + clientId);
                          }
                          return details;
                      }
      
                  };
                  clientDetailsService = m;
              }
              return clientDetailsService;
          }
      
          @Override
          public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
              InMemoryClientDetailsServiceBuilder builder = new InMemoryClientDetailsServiceBuilder() {
      
                  @Override
                  protected void addClient(String clientId, ClientDetails value) {
                      clientDetailsStore.put(clientId, value);
                  }
      
                  @Override
                  protected ClientDetailsService performBuild() {
                      return clientDetailsService();
                  }
              };
              clients.setBuilder(builder);
      
              // @formatter:off
              builder
                  .withClient(&quot;acme&quot;).secret(&quot;acmesecret&quot;)
                      .authorizedGrantTypes(&quot;authorization_code&quot;, &quot;refresh_token&quot;, &quot;password&quot;)
                      .scopes(&quot;openid&quot;, &quot;apim.read&quot;, &quot;apim.write&quot;)
                  .and()
                  .withClient(&quot;trusted&quot;).secret(&quot;shuush&quot;)
                      .authorizedGrantTypes(&quot;client_credentials&quot;)
                      .scopes(&quot;openid&quot;, &quot;apim.read&quot;, &quot;apim.write&quot;)
                      .authorities(&quot;openid&quot;, &quot;apim.read&quot;, &quot;apim.write&quot;);
              // @formatter:on
          }
      
          @Override
          public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
              endpoints.authenticationManager(authenticationManager);
              endpoints.requestFactory(new ScopeMappingOAuth2RequestFactory(clientDetailsService()));
          }
      
  ...
      }
  </code></pre>
  <p><strong>LoginConfig</strong></p>
  <pre class="lang-java prettyprint-override"><code>    Configuration
      @Order(-10)
      protected static class LoginConfig extends WebSecurityConfigurerAdapter {
      
      ....
      
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              // auth.parentAuthenticationManager(authenticationManager);
              // @formatter:off
              auth.inMemoryAuthentication()
                  .withUser(&quot;admin&quot;).password(&quot;admin&quot;)
                      .roles(&quot;APIM.READ&quot;, &quot;APIM.WRITE&quot;)
                  .and()
                  .withUser(&quot;user&quot;).password(&quot;password&quot;)
                      .roles(&quot;APIM.READ&quot;)
                  .and()
                  .withUser(&quot;audit&quot;).password(&quot;audit&quot;)
                      .roles(&quot;APIM.READ&quot;);
              // @formatter:on
          }
      }
  </code></pre>