sam N
sam N

Reputation: 103

Standalone SpringBoot app with OAuth2 authentication

I am working on creating an app using springboot which would consume an API which has OAuth2 authentication. Post successful getting the Bearer code I would be calling another API which would actually give me data for further processing. I have custom OAuth url, authorization code, username, password, secret key, api key. When I searched on internet, none of the example were usign all of these[only secret key, authorization code and api key was getting used.]. Do I need to use username and password as well?

I tried below code [and few other things]. But not able to get through this.

    <code>
        import java.util.ArrayList;
        import java.util.Arrays;
        import java.util.List;
        import javax.xml.bind.DatatypeConverter;
        import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.http.HttpEntity;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.ResponseEntity;
    import org.springframework.http.client.support.BasicAuthorizationInterceptor;
    import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
    import org.springframework.security.oauth2.client.OAuth2RestOperations;
    import org.springframework.security.oauth2.client.OAuth2RestTemplate;
    import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
    import org.springframework.security.oauth2.client.token.AccessTokenRequest;
    import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
    import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonMappingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import lombok.extern.slf4j.Slf4j;
    @Slf4j
    @Component
    public class ApiConsumer {
        @Autowired
        private RestTemplate template;
        @Value("${oauth.api}")
        String url;
        @Value("${oauth.oAuth.url}")
        String oAuthUrl;
        @Value("${oauth.user}")
        String username;
        @Value("${oauth.password}")
        String password;
        @Value("${oauth.apikey}")
        String apiKey;
        @Value("${oauth.secretkey}")
        String apiSecret;
        public String postData() {
            log.info("Call API");
            try {
                String response = consumeApi();
                if (response.equals("200")) {
                    log.info("posting data to another api");
                    // CALL another  API HERE for actual data with bearer code
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "";
        }
        private String consumeApi() throws Exception {
            String authorizationHeader = "Basic "
                    + DatatypeConverter.printBase64Binary((apiKey + ":" + apiSecret).getBytes());
                    // setting up the HTTP Basic Authentication header value
            HttpHeaders requestHeaders = new HttpHeaders();
            // set up HTTP Basic Authentication Header
            requestHeaders.add("Authorization", authorizationHeader);
            requestHeaders.add("Accept", MediaType.APPLICATION_FORM_URLENCODED_VALUE);
            requestHeaders.add("response_type", "code");
            // request entity is created with request headers
            HttpEntity<String> request = new HttpEntity<String>(requestHeaders);
            template.getInterceptors().add(new BasicAuthorizationInterceptor(username, password));
            ResponseEntity<String> result = null;
            try {
                result = template.exchange(oAuthUrl, HttpMethod.POST, request, String.class);
                log.info( result.getBody());
                if (result.getStatusCode() == HttpStatus.OK) {

                    transformData(result.getBody());
                }
                if (result.getStatusCode() != HttpStatus.REQUEST_TIMEOUT) {
                    throw new Exception("Api taking too long to respond! ");
                }
            }
            catch (Exception e) {
                log.error("Api taking too long to respond!");
            }
            return "";
        }
        private void transformData(String body) throws JsonMappingException, JsonProcessingException {
            ObjectMapper mapper = new ObjectMapper();
            List<HeapEntity> heapEntityList = Arrays.asList(mapper.readValue(body, HeapEntity[].class));
            if (heapEntityList != null && heapEntityList.size() > 0) {
                heapEntityList.forEach(i -> i.getPhoneNumber().replaceAll("-", ""));
            }
            log.debug("Size of list is :: " + heapEntityList.size());
            heapEntityList.add(null);

        }

    }
    </code>

Upvotes: 1

Views: 293

Answers (1)

Anar Sultanov
Anar Sultanov

Reputation: 3406

Unfortunately, I cannot give a direct answer to your question, because it is not clear from it which grant type you are trying to use, and this will determine the answer to the question whether you need to use a username and password or not.

I advise you to familiarize yourself with the Section 4 of RFC 6749, in which you will find information on all grant types supported by the standard, and the request parameters they require.

Examples for the Password grant type:

If you need to use the RestTemplate, you can do something like this:

HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString((clientId + ":" + clientSecret).getBytes()));

String body = String.format("grant_type=password&username=%s&password=%s", username, password);

String json = restTemplate.postForObject(tokenUrl, new HttpEntity<>(body, headers), String.class);

Note that the response is a json object containing a token, not the token itself.

Or you can simply use the more appropriate for your purpose OAuth2RestTemplate:

@Bean
public OAuth2RestTemplate oAuth2RestTemplate() {
    ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
    resource.setClientAuthenticationScheme(AuthenticationScheme.form);
    resource.setAccessTokenUri("tokenUrl");
    resource.setClientId("clientId");
    resource.setClientSecret("clientSecret");
    resource.setUsername("username");
    resource.setPassword("password");
    return new OAuth2RestTemplate(resource);
}

Do not forget to add @EnableOAuth2Client to one of your configuration classes.

Upvotes: 1

Related Questions