Page 1 of 3 123 LastLast
Results 1 to 10 of 21

Thread: LinkedIn access token request, 401 Unauthorized

  1. #1
    Join Date
    Jun 2011
    Posts
    3

    Default LinkedIn access token request, 401 Unauthorized


    Hello,

    I'm trying Spring Social 1.0.0.RC1. Section-2 ("2. Service Provider
    'Connect' Framework") of the reference manual provides examples for
    establishing connections to Facebook and Twitter. I have been able
    to use the example code to connect to both providers.

    Now I'm trying to connect to LinkedIn. I'm using the Twitter example
    code as a reference because the Spring Social reference states that
    both Twitter and LinkedIn use OAuth1. The code seems to be successful
    with the first part of the oauth dance which returns an "oauth_token"
    and "oauth_verifier" from LinkedIn.

    But the code encounters an error trying to obtain an access token
    via the "exchangeForAccessToken method. Here is the error:


    org.springframework.web.client.HttpClientErrorExce ption: 401 Unauthorized
    org.springframework.web.client.DefaultResponseErro rHandler.handleError(DefaultResponseErrorHandler.j ava:75)
    org.springframework.web.client.RestTemplate.handle ResponseError(RestTemplate.java:486)
    org.springframework.web.client.RestTemplate.doExec ute(RestTemplate.java:443)
    org.springframework.web.client.RestTemplate.execut e(RestTemplate.java:415)
    org.springframework.web.client.RestTemplate.exchan ge(RestTemplate.java:391)
    org.springframework.social.oauth1.OAuth1Template.e xchangeForToken(OAuth1Template.java:195)
    org.springframework.social.oauth1.OAuth1Template.e xchangeForAccessToken(OAuth1Template.java:133)
    com.hp.it.services.social.socialso.service.LinkedI nManagerImpl.finalizeConnection(LinkedInManagerImp l.java:100)
    com.hp.it.services.social.socialso.controller.Link edInCallbackController.handleRequest(LinkedInCallb ackController.java:50)
    org.springframework.web.servlet.mvc.SimpleControll erHandlerAdapter.handle(SimpleControllerHandlerAda pter.java:48)
    org.springframework.web.servlet.DispatcherServlet. doDispatch(DispatcherServlet.java:790)
    org.springframework.web.servlet.DispatcherServlet. doService(DispatcherServlet.java:719)
    org.springframework.web.servlet.FrameworkServlet.p rocessRequest(FrameworkServlet.java:644)
    org.springframework.web.servlet.FrameworkServlet.d oGet(FrameworkServlet.java:549)
    javax.servlet.http.HttpServlet.service(HttpServlet .java:617)
    javax.servlet.http.HttpServlet.service(HttpServlet .java:717)


    Here's the relevant code:

    LinkedInConnectionFactory connectionFactory = new LinkedInConnectionFactory(apiKey, secretKey);
    OAuth1Operations oAuthOperations = connectionFactory.getOAuthOperations();
    OAuthToken oAuthToken = new OAuthToken(oAuthTokenStr, secretKey);
    OAuthToken accessToken = oAuthOperations.exchangeForAccessToken(
    new AuthorizedRequestToken(oAuthToken, oAuthVerifierStr), null);

    Here's a relevant snipit from my maven pom file:

    <dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-linkedin</artifactId>
    <version>1.0.0.M3</version>
    </dependency>

    Note that I couldn't seem to locate an RC1 version of spring-social-linkedin.

    Does anyone have any ideas of what might be causing the error?

    Thanks.

  2. #2
    Join Date
    Aug 2004
    Location
    Melbourne, FL
    Posts
    2,794

    Default

    Hmm... not sure what is causing this by just looking at the stack trace, but I would definitely upgrade from 1.0.0.M3 to the latest 1.0.0.BUILD-SNAPSHOT for spring-social-linkedin. We haven't released a RC1 of LinkedIn; however, the M3 version is not compatible with the RC1 release of the core Spring Social project. So the error below I would think has something to do with that. Also, Greenhouse, a reference app that uses Spring Social, does also use the LinkedIn module (the latest snapshot) and it is working OK in our tests.

    We chose not to go to RC for the other providers (linkedin, gowalla, tripit, github), since their API bindings are incomplete. For the time being, folks using these modules will have to depend on a nightly snapshot to be able to use them against Spring Social RC1. You're not the first person using the LinkedIn module, though, and running into this. I'm curious... is it complete enough as-is for you in it's present state? I'm concerned about shipping a binding that is missing major parts of the API in a GA form, but if people think it's complete enough we could consider shipping it anyway. Ideally, folks in the community needing the LinkedIn binding will help us complete it and then it can have a proper 1.0.0 GA release...

    Keith
    Keith Donald
    Core Spring Development Team

  3. #3
    Join Date
    Aug 2004
    Location
    Melbourne, FL
    Posts
    2,794

    Default

    Hmm, looking at your code snippet. It seems you're not calling oauthOperations.fetchRequestToken to get a new request token? You're just newing a new OAuth token yourself, and using the consumer secret as your request token secret? If so, that's not going to work. Please see the Spring Social ref docs for a description of the OAuth 1 flow in addition to trying the latest snapshot.
    Keith Donald
    Core Spring Development Team

  4. #4
    Join Date
    Jun 2011
    Posts
    3

    Default


    Hi Keith,

    Thanks for your replies. I've modified my pom for linkedin:

    <dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-linkedin</artifactId>
    <version>1.0.0.BUILD-SNAPSHOT</version>
    </dependency>

    but the code is still encountering the "401 Unauthorized" error.

    Here's a larger snipit of the code which is based on the same code
    for Twitter which is working. My original post may not have included
    enough code perhaps causing confusion.

    // Get a request token...
    LinkedInConnectionFactory connectionFactory =
    new LinkedInConnectionFactory(apiKey, secretKey);
    OAuth1Operations oAuthOperations = connectionFactory.getOAuthOperations();
    OAuthToken requestToken =
    oAuthOperations.fetchRequestToken(oAuthCallbackUrl , null);
    String authorizeUrl =
    oAuthOperations.buildAuthorizeUrl(requestToken.get Value(),
    OAuth1Parameters.NONE);
    response.sendRedirect(authorizeUrl);

    // Wait for callback...

    // Get access token...
    LinkedInConnectionFactory connectionFactory =
    new LinkedInConnectionFactory(apiKey, secretKey);
    OAuth1Operations oAuthOperations = connectionFactory.getOAuthOperations();
    OAuthToken oAuthToken = new OAuthToken(oAuthTokenStr, secretKey);
    AuthorizedRequestToken authorizedRequestToken =
    new AuthorizedRequestToken(oAuthToken, oAuthVerifierStr);
    // The following statement fails...
    OAuthToken accessToken =
    oAuthOperations.exchangeForAccessToken(authorizedR equestToken, null);


    Regarding your question:

    I'm curious... is it complete enough as-is for you in it's present state?

    Currently, I'm just trying to establish a connection with Facebook,
    Twitter, and LinkedIn and perhaps retrieve some profile attributes
    like the user's name. So I don't think I need the complete API to be
    implemented.

    On a separate note, I'd also like to connect with Google and Yahoo and
    will look into the Spring Social extension points to see how that might
    be accomplished. Do you know if there are plans to integrate other
    service providers in the future and roughly when that might happen?

    Thanks.

  5. #5
    Join Date
    Aug 2004
    Location
    Melbourne, FL
    Posts
    2,794

    Default

    The AuthorizedOAuthToken you're passing to exchangeForAccessToken doesn't look right based on this snippet. I expect to see the actual request token and request token secret values used, which are typically held in the OAuthToken instance returned by fetchRequestToken. In our web Controller implementation, we actually cache the OAuthToken returned from fetchRequestToken in the HttpSession, and on the callback we retrieve it and use it to construct an AuthorizedRequestToken, which is then passed to exchangeForAccessToken. It seems your implementation is using a 'oauthTokenStr' variable for the token value -- declared somewhere else -- and reusing the consumer secret as the request token secret, which is not correct and could lead to a 401 error. Where is your request token secret?

    You might want to review the generic oauth controller code we have across ConnectController and ConnectSupport in spring-social-web, and compare our code that already does all this stuff with yours.

    Keith
    Last edited by Keith Donald; Jun 28th, 2011 at 12:06 PM.
    Keith Donald
    Core Spring Development Team

  6. #6
    Join Date
    Jun 2011
    Posts
    3

    Default

    Hi Keith,

    Ahhhh, now it works! Your explanation was spot on -- I re-checked the
    AuthorizedRequestToken constructor in the API doc and I immediately
    understood what you were saying and realized my error. Caching and
    reusing the request token in HTTP session solved the problem.
    Thanks for your patience and your detailed responses.

  7. #7
    Join Date
    Oct 2011
    Posts
    9

    Default

    Can you please share your application to connect to linkedin. Just need basic connectivity. A page where user simply clicks connect to linkedIn, if he is loggedIn it asks for access authorization else transfers for linkedIn login page. I have connected to facebook using spring social, but it fails to connect to linkedin. If possible please email your code at gaurav_6358@yahoo.com I am stuck of in my application. Any help would be appreciated.

  8. #8
    Join Date
    Aug 2004
    Posts
    1,072

    Default

    I don't have a LinkedIn sample like that immediately available, but it wouldn't be much different than how the Spring Social Showcase (https://github.com/SpringSource/spri...ocial-showcase) connects with Twitter. The main difference would be in SocialConfig.java where the TwitterConnectionFactory is configured. Instead of TwitterConnectionFactory, you'd use LinkedInConnectionFactory and provide it with your app's LinkedIn consumer key and secret.

    I'd try checking out the showcase code and tweaking it to use LinkedIn instead of Twitter. Let us know how it goes or if you run into any trouble.
    Craig Walls
    Spring Social Project Lead

  9. #9
    Join Date
    Oct 2011
    Posts
    9

    Default

    I tried to use showcase example of twitter for linkedIn. But i could not connect. it says 401 athurization error.

  10. #10
    Join Date
    Oct 2011
    Posts
    9

    Default

    I tried using quickstart sample application. it was for facebook, i converted it to twitter and it runs successfully. But when i change from twitter to linkedin it gives error in controllers.xml It givers error in creating reference of linkedinApi
    <bean class="org.springframework.social.quickstart.HomeC ontroller">
    <constructor-arg ref="linkedinapi" />
    </bean>

    controllers.xml file is as below

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schem...ng-mvc-3.0.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- Controls rendering of the home page once a user has signed in -->
    <!-- <bean class="org.springframework.social.quickstart.HomeC ontroller">
    <constructor-arg ref="facebook" />
    </bean> -->

    <!-- <bean class="org.springframework.social.quickstart.HomeC ontroller">
    <constructor-arg ref="twitter" />
    </bean> -->

    <bean class="org.springframework.social.quickstart.HomeC ontroller">
    <constructor-arg ref="linkedinapi" />
    </bean>

    <!-- Allows users to sign-in with their provider accounts. -->
    <bean class="org.springframework.social.connect.web.Prov iderSignInController">
    <constructor-arg ref="connectionFactoryLocator" />
    <constructor-arg ref="usersConnectionRepository" />
    <constructor-arg>
    <bean class="org.springframework.social.quickstart.user. SimpleSignInAdapter" />
    </constructor-arg>
    </bean>

    <mvc:view-controller path="/signin" />

    <mvc:view-controller path="/signout" />

    </beans>


    -------------------------------------------------------------------------------------------------------------

    @Controller
    public class HomeController {

    private final LinkedInApi linkedinapi;






    @Inject
    public HomeController(LinkedInApi linkedinapi) {
    this.linkedinapi = linkedinapi;
    }

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Model model) {
    System.out.println("Home controller : home");
    model.addAttribute("profile", linkedinapi.getUserProfile());
    return "home";
    }


    /*private final Twitter twitter;




    @Inject
    public HomeController(Twitter twitter) {
    this.twitter = twitter;
    }

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Model model) {
    System.out.println("Home controller : home");
    model.addAttribute("profile", twitter.userOperations().getUserProfile());
    return "home";
    }*/

    }



    --------------------------------------------------------------------------------------------------
    /**
    * Spring Social Configuration.
    * @author Keith Donald
    */
    @Configuration
    public class SocialConfig {

    /*@Value("${facebook.clientId}")
    private String facebookClientId;

    @Value("${facebook.clientSecret}")
    private String facebookClientSecret;*/

    @Value("${twitter.consumerKey}")
    private String twitterConsumerKey;

    @Value("${twitter.consumerSecret}")
    private String twitterConsumerSecret;

    @Value("${linkedin.consumerKey}")
    private String linkedinClientId;

    @Value("${linkedin.consumerSecret}")
    private String linkedinClientSecret;

    @Inject
    private DataSource dataSource;

    /**
    * When a new provider is added to the app, register its {@link ConnectionFactory} here.
    * @see FacebookConnectionFactory
    */
    @Bean
    public ConnectionFactoryLocator connectionFactoryLocator() {
    ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
    //registry.addConnectionFactory(new FacebookConnectionFactory(facebookClientId, facebookClientSecret));
    //registry.addConnectionFactory(new TwitterConnectionFactory(twitterConsumerKey,twitte rConsumerSecret));
    registry.addConnectionFactory(new LinkedInConnectionFactory(linkedinClientId,linkedi nClientSecret));

    return registry;
    }

    /**
    * Singleton data access object providing access to connections across all users.
    */
    @Bean
    public UsersConnectionRepository usersConnectionRepository() {
    JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(dataSource,
    connectionFactoryLocator(), Encryptors.noOpText());
    repository.setConnectionSignUp(new SimpleConnectionSignUp());
    return repository;
    }

    /**
    * Request-scoped data access object providing access to the current user's connections.
    */
    @Bean
    @Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
    public ConnectionRepository connectionRepository() {
    /*Authentication authentication = SecurityContextHolder.getContext().getAuthenticati on();
    if (authentication == null) {
    throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
    }
    return usersConnectionRepository().createConnectionReposi tory(authentication.getName());*/
    User user = SecurityContext.getCurrentUser();
    return usersConnectionRepository().createConnectionReposi tory(user.getId());
    }

    /**
    * A proxy to a request-scoped object representing the current user's primary Facebook account.
    * @throws NotConnectedException if the user is not connected to facebook.
    */
    /*@Bean
    @Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
    public Facebook facebook() {
    return connectionRepository().getPrimaryConnection(Facebo ok.class).getApi();
    }*/

    /*@Bean
    @Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
    public Twitter twitter() {
    return connectionRepository().getPrimaryConnection(Twitte r.class).getApi();
    Connection<Twitter> twitter = connectionRepository().findPrimaryConnection(Twitt er.class);
    return twitter != null ? twitter.getApi() : new TwitterTemplate();
    }*/

    @Bean
    @Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
    public LinkedInApi linkedIn(){
    return connectionRepository().getPrimaryConnection(Linked InApi.class).getApi();
    /*Connection<LinkedInApi> linkedIn = connectionRepository().findPrimaryConnection(Linke dInApi.class);
    return linkedIn != null ? linkedIn.getApi() : null;*/
    }

    }

    ------------------------------------------------------------------------------------------------------------------

    public final class UserInterceptor extends HandlerInterceptorAdapter {

    private final UsersConnectionRepository connectionRepository;

    private final UserCookieGenerator userCookieGenerator = new UserCookieGenerator();

    public UserInterceptor(UsersConnectionRepository connectionRepository) {
    System.out.println("UserInterceptor : ");
    this.connectionRepository = connectionRepository;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("UserInterceptor : preHandle");
    rememberUser(request, response);
    handleSignOut(request, response);
    if (SecurityContext.userSignedIn() || requestForSignIn(request)) {
    return true;
    } else {
    return requireSignIn(request, response);
    }
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    System.out.println("UserInterceptor : afterCompletion");
    SecurityContext.remove();
    }

    // internal helpers

    private void rememberUser(HttpServletRequest request, HttpServletResponse response) {
    System.out.println("UserInterceptor : rememberUser");
    String userId = userCookieGenerator.readCookieValue(request);
    if (userId == null) {
    return;
    }
    if (!userNotFound(userId)) {
    userCookieGenerator.removeCookie(response);
    return;
    }
    SecurityContext.setCurrentUser(new User(userId));
    }

    private void handleSignOut(HttpServletRequest request, HttpServletResponse response) {
    System.out.println("UserInterceptor : handleSignOut");
    if (SecurityContext.userSignedIn() && request.getServletPath().startsWith("/signout")) {
    connectionRepository.createConnectionRepository(Se curityContext.getCurrentUser().getId()).removeConn ections("linkedin");
    userCookieGenerator.removeCookie(response);
    SecurityContext.remove();
    }
    }

    private boolean requestForSignIn(HttpServletRequest request) {
    System.out.println("UserInterceptor : requestForSignIn");
    return request.getServletPath().startsWith("/signin");
    }

    private boolean requireSignIn(HttpServletRequest request, HttpServletResponse response) throws Exception {
    System.out.println("UserInterceptor : requireSignIn");
    new RedirectView("/signin", true).render(null, request, response);
    return false;
    }

    /*private boolean userNotFound(String userId) {
    System.out.println("UserInterceptor : userNotFound");
    // doesn't bother checking a local user database: simply checks if the userId is connected to Facebook
    return connectionRepository.createConnectionRepository(us erId).findPrimaryConnection(Facebook.class) != null;
    }*/

    /*private boolean userNotFound(String userId) {
    System.out.println("UserInterceptor : userNotFound");
    // doesn't bother checking a local user database: simply checks if the userId is connected to Facebook
    return connectionRepository.createConnectionRepository(us erId).findPrimaryConnection(Twitter.class) != null;
    }*/

    private boolean userNotFound(String userId) {
    System.out.println("UserInterceptor : userNotFound");
    // doesn't bother checking a local user database: simply checks if the userId is connected to Facebook
    return connectionRepository.createConnectionRepository(us erId).findPrimaryConnection(LinkedInApi.class) != null;
    }

    }

    --------------------------------------------------------------------------------------------------------------------------

    Any help would be greatly appreciated. I can also email you code for twitter quickstart if required. In case code is required please provide me with your emailId.

    thanks,
    Gaurav

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •