Watson Workspace will no longer be available after February 28, 2019. Learn more.


Mutations in graphql



  • Avatar
    Vitalijus Rudzinskas (Edited )

    1. I think graphQL explorer is flaky.
    Go to:

    And quickly Ctrl-C Ctrl-V your create space query and run it. This should work.
    This means YOU are creating the space via query instead of workspace interface. If you want your app to create spaces, your app will have to work on behalf of user, get user access token and all the good stuff.

    2. createTargetedMessage is strictly app thing and it should be implemented and tested in an app - user clicks annotation or button and in under 10 seconds the app sends him the targetedMessage with text, buttons and whatnot.

    So I guess you will have to create and test that query in the app code, your chosen IDE debugger and google are your friends.

    From your code samples I assume your first query fails because you are using app token where you should be using user access token with your app acting on behalf or user. And I assume your second query fails cause you are hitting the wrong API, try to see what header it is setting and then try to set the header to "x-graphql-view: BETA,PUBLIC" with app jwt token.

    If none of above makes any sense to you, you should probably start explaining what programming language are you coding in, what did you start with, what do you have implemented already and what are you trying to do next.

  • Avatar
    Miguel Estrada

    For issue 1:  Correct.  The JWT must be of a human using a client.  Can't be an app using itself as a client.  An app can ask a human to authorize it to use his/her identity via the run-as-user flow.


    For issue 2: The createTargetedMessage mutation is used as a response to the actionSelected mutation.  When the Workspace client issues this mutation it will go into a 10second period waiting for a targeted message.  If it does not receive one then it will get out of this state.  This means that if you are using a graphQL explorer type tool or explicitly sending the message based on your own input you must do it during this time window.


    Also, there is a GraphQL IDE in open source you can download which allows you to use other JWTs like the ones you create via the client-credentials flow to allow an app to use itself as an actor+client.  When using the graphQL explorer at developer.watsonwork.ibm.com you will be using a JWT based on how you logged in there and can't use (today) those from an app.

  • Avatar
    Aman Shah

    Thanks for the precise and helpful response.

    Can you guide me about how to generate valid value for "state" query parameter in "/oauth/authorize" API on server side.

    I am getting a response as below:

    <!DOCTYPE html>
    <div id="ticker"></div>

    var authMethod = "Unknown";
    if (authMethod != null && authMethod == "failover-password" ) {
    location.href = "/fcsso/fcsso";
    } else if (location.pathname == "/" || location.pathname.search("/v1") == 0 || location.pathname.search("/ssoconfig") == 0) {
    location.href = "/idaas/mtfim/sps/idaas/login?login_type=local";
    } else {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "/idaas/mtfim/sps/idaas/login/ibm_security_logout");
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    var script = document.createElement("script");
    script.src = "/idaas/mtfim/sps/ac/js/info.js";
    script.onload = function() {
    sendSession(0, function() {
    var queryIndex = location.href.indexOf("?");
    if (queryIndex == -1) {
    location.href = "/idaas/mtfim/sps/idaas/login";
    } else {
    var query = location.href.substring(queryIndex + 1);
    location.href = "/idaas/mtfim/sps/idaas/login?" + query;



    setInterval(function() {
    var ticker = document.getElementById("ticker");
    ticker.innerHTML = ticker.innerHTML + ". ";
    }, 100);



    "method": "GET",
    }, function(err, response, body){
    console.log(body); //above mentioned response

    And not getting any hit to redirect uri provided in the query component "redirect_uri" and also in "Run as User section" in App settings.
    app.get("/callback", (req, res) => {
    What silly thing am I doing again, please let me know.
  • Avatar
    Vitalijus Rudzinskas (Edited )

    Never had to define it, but in my app it is: 

    STATE_VALUE = "123456678"

    You can try that, but I suspect it is just random value that has to match in a couple of places.

    I just checked:
    1. It has to be in your app (for me it is STATE_VALUE = "123456678" in WatsonWorkConstants.java)

    2. It has to be in the end of the URL the user is using to authorize the app to act on his behalf. (For me it is https://api.watsonwork.ibm.com/oauth/authorize?response_type=code&client_id=[ APP_ID ]&redirect_uri=https://[ MY_NGROK ]/oauthCallback&state=123456678

    If I use the same value, then request succeeds and my app gets authorized by user, gets his access token and refresh token. If it doesn't match, my app gets IllegalArgumentException after assert failure.

    I think it is supposed to be protection against some sort of man-in-the middle attack.

    Also I have now just changed it to a new random value, for good measure.

  • Avatar
    Aman Shah

    Okay, if its not an issue with the "state" parameter then whats the meaning of the response as stated in my previous post. Also there's no hit to my redirect_uri.


    Request you to please refer my previous post ignoring question about state value and point out the issues about, why my app is not getting authorised and not receiving hits to "/callback".


    Thanks for your effort!

  • Avatar
    Vitalijus Rudzinskas (Edited )

    Your app should have two webhooks: "/webhook" and "/callback"

    In your browser you go to the URL like: "https://api.watsonwork.ibm.com/oauth/authorize?response_type=code&client_id=[APP_ID]&redirect_uri=https://[MY_NGROK]/oauthCallback&state=123456678"

    This is request to authorize the app to work on your behalf, it provides Watson Workspace with your appID and the webhook where Watson Workspace can reach your app.

    Then Watson Workspace knows what app to provide with refresh token and access token to work on YOUR behalf. 

    Except it doesn't know who you are, you are just a guy who went to that strange URL, so it takes you to IBM login page, where you enter your ibmID and password.

    Then it has everything a user, appid and webhook (oauthCallback) to send credentials to.

    After you login on that page it then sends credentials (access token and refresh token) that allow app to work on your behalf to the [NGROK]/oauthcallback address you provided in your URL.

    At this point you will have user access token that you can use to set in the header of the graphQL query and the Watson Workspace will interpret that query as the app acting on your behalf and allow it to run the query.

    If you do a "createMessage" query with that token in the header in your app, the message will appear in workspace looking as if you posted that message.

    Your goal is to correctly set up the two webhooks, use correct appID, webhook secret and app secret and form the URL correctly that will eventually take you to Watson Workspace IBM ID login page and then hit your oauthcallback webhook with the tokens to be used by your app.

    Keep trying, took me a couple of days, first time around.
    I believe in you.

    If you get completely stuck and lost, get some app that already has "working on behalf of user" implemented from https://github.com/watsonwork and debug and study that example.

Please sign in to leave a comment.