Getting "invalid_grant" while navigation on SugarCRM

Hi.

I browse SugarCRM inside several iFrames in my Web Application. The SessionID is always the same.

When I log in SugarCRM I can see a "/rest/v10/oauth2/token" with my credentials and I get the following reply:

{"access_token":"tokenAccess","expires_in":3600,"token_type":"bearer","scope":null,"refresh_token":"tokenRefresh","refresh_expires_in":1209600,"download_token":"tokenDownload"}

After some minutes, while navigating, I'm redirected to the login page. When that happens I see the following request to "/rest/v10/oauth2/token":

{"grant_type":"refresh_token","client_id":"sugar","client_secret":"","refresh_token":"refreshToken","platform":"base","refresh":true}

But I get the response:

{"error":"invalid_grant","error_message":"Invalid refresh token"}

Inside SugarCRM I have some custom code that invokes WebServices on my side. That WebServices requests tokens to SugarCRM with a different user that is navigating BUT in some cases I invoke "/rest/v10/oauth2/sudo/ with the user that is navigating.

Anyone have an idea of why the "Invalid refresh token"?

Thanks in advance.

 

Parents Reply Children
  • Hi,

    Thanks for replying.

    This is my method to perform the "special API user" authentication:

    public static string Authenticate(string sugarURL, string clientID = null, string clientSecret = null, string username = null, string password = null)
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sugarURL + "oauth2/token");
                request.Method = "POST";
                request.ContentType = "application/json";

                TokenRequest t = new TokenRequest()
                {
                    client_id = clientID,
                    client_secret = clientSecret,
                    username = username,
                    password = password
                };

                DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(TokenRequest));
                using (Stream stream = request.GetRequestStream())
                {
                    ser.WriteObject(stream, t);
                }

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                using (StreamReader responseString = new StreamReader(response.GetResponseStream()))
                {
                    ser = new DataContractJsonSerializer(typeof(TokenResponse));
                    TokenResponse r = (TokenResponse)ser.ReadObject(responseString.BaseStream);
                    return r.access_token;
                }
            }

    This is the method to request the user token. It receives a "otherUsername" which is the user navigating SugarCRM and a "authToken" which was obtained previously by calling "Authenticate".

    public static string RequestUserToken(string sugarURL, string otherUsername, string authToken = null, string clientID = null, string clientSecret = null, string username = null, string password = null)
            {
                sugarURL = "https://" + sugarURL + "/rest/v10/";

                if (string.IsNullOrWhiteSpace(authToken))
                {
                    authToken = Authenticate(sugarURL, clientID, clientSecret, username, password);
                }

                //Structure need by SugarCRM to make this request
                sugarURL = sugarURL + "oauth2/sudo/" + otherUsername;
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sugarURL);

                request.Method = "POST";
                request.Headers.Add("oauth-token", authToken);

                TokenRequest t = new TokenRequest()
                {
                    client_id = clientID,
                    client_secret = clientSecret,
                    username = username,
                    password = password
                };

                DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(TokenRequest));
                using (Stream stream = request.GetRequestStream())
                {
                    ser.WriteObject(stream, t);
                }

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                using (StreamReader responseString = new StreamReader(response.GetResponseStream()))
                {
                    ser = new DataContractJsonSerializer(typeof(TokenResponse));
                    TokenResponse r = (TokenResponse)ser.ReadObject(responseString.BaseStream);
                    return r.access_token;
                }
            }

    This is the code that adds a call:

    public string AddNewCall(string sugarURL, string callName, string dateStart, string direction, string assignedUsername, 
                                    String username, String password, String key, String secret, string oauthToken = null, string description = "None",
                                    string status = "Scheduled")
            {
                string addCallResult = DoRequest.Call(
                    sugarURL,
                    "Calls",
                    "POST",
                    new Dictionary<string, string>()
                    {
                        { "name", callName },
                        {"description", description },
                        {"date_start", dateStart },
                        {"duration_minutes", durationMinutes },
                        {"direction", direction },
                        {"status", status },
                        {"assigned_user_id", assignedUsername }
                    },
                    oauthToken, key, secret, username, password);

                AddCallResponse response = null;
                using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(addCallResult)))
                {
                    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(AddCallResponse));
                    response = (AddCallResponse)ser.ReadObject(ms);
                }

                return response.id;
            }

    public static string Call(string sugarURL, string url, string method, Dictionary<string, string> arguments, string authToken = null, string clientID = null, string clientSecret = null, string username = null, string password = null)
            {
                sugarURL = "https://" + sugarURL + "/rest/v10/";

                if (string.IsNullOrWhiteSpace(authToken))
                {
                    authToken = Authenticate(sugarURL, clientID, clientSecret, username, password);
                }
               
                if (method == "GET")
                {
                    string queryParameters = "";
                    if (arguments != null)
                    {
                        foreach (string key in arguments.Keys)
                        {
                            queryParameters += WebUtility.UrlEncode(key) + "=" + WebUtility.UrlEncode(arguments[key]) + "&";
                        }
                    }

                    if (!string.IsNullOrWhiteSpace(queryParameters))
                    {
                        queryParameters = "?" + queryParameters.Substring(0, queryParameters.Length-1);
                    }

                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sugarURL + url + queryParameters);
                    request.Method = "GET";
                    request.Headers.Add("oauth-token", authToken);

                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                    {
                        return reader.ReadToEnd();
                    }
                }

                if(method == "POST")
                {
                    string queryParameters = "";
                    if (arguments != null)
                    {
                        foreach (string key in arguments.Keys)
                        {
                            queryParameters += WebUtility.UrlEncode(key) + "=" + WebUtility.UrlEncode(arguments[key]) + "&";
                        }
                    }

                    if (!string.IsNullOrWhiteSpace(queryParameters))
                    {
                        queryParameters = "?" + queryParameters.Substring(0, queryParameters.Length - 1);
                    }

                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sugarURL + url + "/" + queryParameters);

                    request.Method = "POST";
                    request.Headers.Add("oauth-token", authToken);

                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                    {
                        return reader.ReadToEnd();
                    }
                }

                if (method == "PUT")
                {
                    string queryParameters = "";
                    if (arguments != null)
                    {
                        foreach (string key in arguments.Keys)
                        {
                            queryParameters += WebUtility.UrlEncode(key) + "=" + WebUtility.UrlEncode(arguments[key]) + "&";
                        }
                    }

                    if (!string.IsNullOrWhiteSpace(queryParameters))
                    {
                        queryParameters = "?" + queryParameters.Substring(0, queryParameters.Length - 1);
                    }

                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sugarURL + url + queryParameters);
                    request.Method = "PUT";
                    request.Headers.Add("oauth-token", authToken);

                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                    {
                        return reader.ReadToEnd();
                    }
                }

                return null;
            }

    So, basically I have this:

    // key & secret -> OAuth Key 2.0 created in Sugar
    // username & password -> Special API user
    string oauthToken = DoRequest.Authenticate(sugarREST, key, secret, username, password);
    ...
    ...
    ...
    // sugarUsername -> Another user username
    // remaining parameters will be ignored
    sugarToken = DoRequest.RequestUserToken(SugarURL, sugarUsername, oauthToken, key, secret, username, password);
    ...
    ...
    ...
    callID = newCall.AddNewCall(SugarURL, callName, ConstructDateString(DateTime.UtcNow), direction, sugarID, username, password, key, secret, sugarToken, "None", "Scheduled", "0", "None", mediaType);

    Do you see anything wrong?

  • Hi Nuno,

    Here is the first question, looking at your

    public static string RequestUserToken

    Why do you pass your username and password one more time? 

      TokenRequest t = new TokenRequest()
                {
                    client_id = clientID,
                    client_secret = clientSecret,
                    username = username,
                    password = password
                };

    I think this is causing your user to be kicked out. Take a look at /oauth2/sudo/:user_name POST Endpoint. It expects your user to be an Admin and you don't need to pass the username and password. All you need username as a third parameter( /oauth2/sudo/:username)

    Let me know if this helps. 

    Best Regards
    Tevfik Tümer
    Developer Support Engineer

  • OMG!

    I've Code Reviewed this code (I'm not the developer) and I don't know how I've missed this!

    It's working!

    Thanks a lot Tevfik Tümer!

  • Hi Nuno,

    I'm glad it works now

    Best Regards
    Tevfik Tümer
    Developer Support Engineer

  • Hi Nuno,

    Even after changing the code? 

    I don't have any environment for you to check this code. 

    If it would be php, i would check here in my local machine. 

    I will take a look at this later on one more time. See if i can catch another problem. 

    Best Regards
    Tevfik Tümer
    Developer Support Engineer

  • Hi Nuno,


    I'm glad that you figured that out  I actually mentioned that in one of my posts here as well.

    Best Regards
    Tevfik Tümer
    Developer Support Engineer