Debugging Jive Connects Communications Issues

Version 3

     

    During application development using Jive Connects to communicate with a remote server, especially one that requires authentication, it can be tricky to debug what is actually happening.  Here's a debugging tip, which requires only the developer console (or Firebug).

     

    The key is the understanding that Jive Connects API calls show up in the network log of your console with some distinctive characteristics.  In particular, they do a POST to an "rpc" endpoint with an inbound and outbound JSON message structures as described below.  (Note that the same thing applies to Jive Core API calls -- the only difference will be the "method" values on the inbound request).

     

    Here's the JSON for an inbound request to the Quotes Demo application, after being prettified by jsonlint.com:

     

    [
        {
            "method": "jive.connects.get",
            "id": "jive.connects.get",
            "params": {
                "alias": "quotes",
                "headers": {
                    "Accept": [
                        "application/json"
                    ]
                },
                "href": "/quotes",
                "params": {
                    "direction": "ascending",
                    "index": 0,
                    "limit": 5,
                    "offset": 0,
                    "order": "dueDate"
                },
                "userId": "@viewer",
                "groupId": "@self"
            }
        }
    ]

     

    The important fields are as follows:

     

    Field NameDescription
    idThe identifier of this request in a batch, if you combine multiple requests.  Defaults to the same as the method name on individual requests.
    methodThe internal identifier of the API call being performed.  The "jive.connects" prefix identifies this as a Jive Connects call, with the last word being the name of the HTTP verb for this call.
    params.aliasThe name of the Jive Connects service alias to use for this request.
    params.headersThe HTTP headers that you sent along on this request (if any).
    params.hrefThe partial path that you sent along on this request.
    params.paramsThe query parameters that you sent along on this request (if any).

     

    A successful reply from the server looks like this:

     

    [
        {
            "id": "jive.connects.get",
            "result": {
                "headers": {
                    "cache-control": [
                        "private"
                    ],
                    "content-type": [
                        "application/json"
                    ],
                    "expires": [
                        "Thu, 01 Jan 1970 00:00:00 GMT"
                    ],
                    "transfer-encoding": [
                        "chunked"
                    ],
                    "set-cookie": [
                        "JSESSIONID=jT6F0FSMOtsN8nHWSmHttA;Path=/"
                    ],
                    "server": [
                        "Google Frontend"
                    ],
                    "date": [
                        "Fri, 16 Mar 2012 18:02:55 GMT"
                    ],
                    "vary": [
                        "Accept-Encoding"
                    ]
                },
                "content": [
                    { ... the response body content, elided for brevity ... }
                ],
                "status": 200
            }
        }
    ]

     

    The important fields here are:

     

    Field NameDescription
    idThe identifier of this response, matching the one submitted on the request.
    result.headersThe HTTP headers that were returned by the remote server.
    result.contentThe response body returned by the remote server (in JSON, XML, or whatever format you are using).
    result.statusThe HTTP status code returned by the remote server (in this case, a 200).

     

    Now, lets look at a very common error case.  If I go to User Settings --> Preferences --> Connects Services, I can remove my credentials for the Quotes service (it uses HTTP Basic).  Now if I go back and issue exactly the same request as shown above, I get the 401 status back that triggers my app to call the "reconfigure" API:

     

     

    [
        {
            "id": "jive.connects.get",
            "result": {
                "headers": {
                    "cache-control": [
                        "private"
                    ],
                    "content-type": [
                        "text/html; charset=utf-8"
                    ],
                    "transfer-encoding": [
                        "chunked"
                    ],
                    "www-authenticate": [
                        "Basic realm=\"Quotes Service\""
                    ],
                    "set-cookie": [
                        "JSESSIONID=61DsP3qk0VYrKopQWI78iQ;Path=/"
                    ],
                    "server": [
                        "Google Frontend"
                    ],
                    "date": [
                        "Fri, 16 Mar 2012 18:26:35 GMT"
                    ],
                    "vary": [
                        "Accept-Encoding"
                    ]
                },
                "content": {
                    "content": "<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n<title>401 Full authentication is required to access this resource</title>\n</head>\n<body text=#000000 bgcolor=#ffffff>\n<h1>Error: Full authentication is required to access this resource</h1>\n</body></html>"
                },
                "error": {
                    "message": "Unauthorized",
                    "code": 401
                },
                "status": 401
            }
        }
    ]

     

    This time, we see a couple of interesting things:

    • An error field containing a message, and the HTTP status code (401 meaning "Unauthorized")
    • The content field in this case won't really be relevant, but it will commonly be (as it is here) the server's HTML page that says you must be authenticated to call this URI.
    • In the headers we see the WWW-Authenticate header that says what kind of authentication this server is expecting (in this case "Basic").

     

    Armed with the information above, you should be able to determine whether your app is sending the correct information, and whether your server is returning the expected response, and get your application up and running quickly.

     


     

    Jive Connects Error Codes

     

    When utilizing Jive Connects, once in a while you will receive an error response (with a 4xx or 5xx HTTP status).  In such a case, Jive Connects will return you a nicely formatted error message like this:

    {
      "error" {
        "code" : 1014,
        "message" : "Connection reset"
      },
      "status" : 502
    }

     

    The status property is the HTTP status code that was returned by the server, and the following table describes the (current) valid values for the code field:

     

    CodeDescription
    1001No request body is allowed on DELETE or GET requests.
    1002Application instance has been removed.
    1003The current readiness state of this application instance cannot be determined.
    1004

    This application instance needs to be configured before it can be used.

    1005This application has been disabled.
    1006This application is not in a READY state.
    1007The connection alias specified on this request is missing or invalid.
    1008The user id associated with this application instance is invalid.
    1009The requested connection alias has been disabled.
    1010The requested Jive Connects service has been disabled.
    1011The requesting user is not authorized to use the requested Jive Connects service.
    1012The SSL handshake with the remote service has failed (typically a problem with the server certificate).
    1013The URI for this request has invalid syntax.
    1014An I/O exception has occurred when communicating with the remote server.
    1015An exception has occurred in the Jive server while handling this request.
    1016Read timeout waiting for the remote server to respond to a request.
    1017Connection timeout waiting for the remote server to accept a socket connection.
    1018Cannot allocate an HTTP connection from the resource pool in the Jive server.
    1019Requesting user is not authorized to access the requested resource on the remote server.
    1020Invalid value in a request to update connection pool timeouts (Jive admins only)

     


     

    Understanding 401 Responses in Jive Connects

    As you know if you've used Jive Connects, the first time your application tries to contact a remote server that requires user authentication, it will report back to you the HTTP status 401 error that Connects received back from the remote server.  The typical behavior at this point is for the application to request reconfiguration of user credentials, like this in your callback function:

     

     

    function callback(response) {     if (response.error) {         if (response.error.code == 401) {             osapi.jive.connects.reconfigure("quotes", response, function(feedback) {                 // See discussion below             });         }         else {             // Deal with errors other than 401         }     }     else {         // Process the received data     } } 

     

     

    When the reconfigure() function is called, Jive Connects will challenge the user for credentials (based on the authentication style selected for this service), and then return feedback to the callback function passed to the reconfigure() call.  There are actually four different things that could have happened, so let's discuss what you will see:

     

    User Entered Correct Credentials and Clicked "Approve"

     

    The feedback object sent to the reconfigure callback will include the alias identifying which Jive Connects connection was reconfigured, and there will be no error block:

     

    {   "alias" : "quotes" } 

     

    Typically, the application will retry the request that triggered the 401 response, which will now succeed and the data can be processed as usual.  As long as the credentials for this user remain valid, Jive Connects will transparently include the credentials on each request, and data will flow normally.

     

    User Clicked "Deny"

     

    This indicates that the user declines to provide credentials for this service.  You can tell this happened because the feedback you get back will be different:

     

    {   "alias" : "quotes",   "error" : {     "code" : 401,     "message" : "The user denied this operation."   } } 

     

    What happens next depends on whether the application can proceed without access to this particular service (i.e. usage of the service is optional).  In that case, it should just continue operating, keeping track of the fact that the user refused to provide credentials.

     

    User Closed the Authentication Dialog Popup Without Clicking "Approve" or "Deny"

     

    The feedback is again slightly different, to tell you what happened:

    {   "alias" : "quotes",   "error" : {     "code" : 401,     "message" : "The user cancelled this operation"   } }

     

    What do we do now?  Again, that depends on whether the application absolutely requires this service, or whether it can do something without it.  Generally, the app should treat this case just as if the user had clicked "Deny".

     

    User Entered Incorrect Credentials and Clicked "Approve"

     

    The feedback response in this scenario will be exactly like the case above where the user entered correct credentials and clicked "Approve".

    {   "alias" : "quotes" }  

     

    "Huh?" you might ask.  What's going on here?

     

    This feedback makes more sense when we remember exactly what a reconfigure call actually does:

    • Asks the user for credentials (of the appropriate style) for the configured service
    • If the user clicks "Approve", stores those credentials in the Jive database (suitably encrypted, of course).
    • Returns the feedback above to your application.

     

    Jive Connects cannot tell whether the credentials are actually correct or not, because it does not retry the previous request.  This is for two reasons:

    • Whether or not a retry is appropriate is up to the application logic, and Jive Connects has no way to find out what the app wants to do.
    • The previous 401 response (from the remote server) was returned to the app already, and Jive resources associated with that request have already been released (each Jive Connects request stands alone), so Jive no longer has the information it would need to perform a retry even if it knew that a retry was appropriate.

     

    The net effect is that the application is totally in charge of performing requests to the remote server.  In this particular scenario, a retry request will trigger another 401 response (because the credentials are not valid).  A simplistic implementation of "retry on a 401 response until we get something else" will likely annoy your user with repeated requests to reconfigure credentials.  It would be appropriate to keep track of whether you get a 401, do the reconfigure call, and then get a 401 on the retry, so you can provide additional information to the user ... perhaps a message like "It appears that the credentials you just entered are not being recognized by the service.  Would you like to try entering them again?" so that the user can determine whether they want to deal with correcting the credentials now, or do something else with the app first.