Jump to content

Oauth2 Authorisation and IIS


 Share

Recommended Posts

Hi,

I'm working in C# / Visual Studio 2019 (this is a Windows Desktop application not a web app), and using Postman as a test tool for the API. I can and have obtained access tokens using Postman and its own callback uri, but when I try and repeat it using a callback url to my own laptop I get the 'Authorise Application Error' screen. Repeating the exercise from my C# project gives the same error, although I have checked the request string carefully against that generated by Postman.

I'm wondering if the underlying problem is that I have IIS running on my laptop? My callback uri is based on localhost. Is there any additional configuration I need to do make the api work under this scenario?

Many thanks

Reg

Link to comment
Share on other sites

I am a new Sage developer and have reached the same point.  Postman generates tokens which can then be used to generate successful API requests but my C# code (even using the SageOne API Sample) fails with Authorise Application Error.  Any pointers, especially other examples of the OAuth logic using ASP.NET Framework WebPages  C# rather than .NET Core, would be appreciated.

Link to comment
Share on other sites

I have noticed that the code that is returned (and the one in the sample code from Authentication | Sage Developer | Accounting) starts with "GB/" which looks like to country code.  The sample request for a token has stripped this off.  Is this correct?

Response:
GET https://myapp.com/auth/callback?code=GB%2F12abcxxxxxxxxxxxxf7d&country=GB&state=random_string

Request:

POST https://oauth.accounting.sage.com/token
Content-Type: application/x-www-form-urlencoded

client_id=4b6xxxxxxx710
&client_secret=iNuxxxxxxxxxxtm9
&code=12axxxxxxxxxxxxf7d
&grant_type=authorization_code
&redirect_uri=https://myapp.com/auth/callback
Link to comment
Share on other sites

Hi both, thank you for your questions.

We're not aware of any such scenario where iis could potentially block a localhost callback url but, given the many permutations of iis configuration it may be possible to cause a situation where this does occur.

Did you change the callback url for your registered app in the developer self service?  It's vital that the callback url registered against your app matches that of the localhost address.

We're looking to improve the examples in the coming months with the aim of providing a more up to date c# guide.
 

@Stuart Eastland are you able to share your stripped down oAuth code with us please?

Kind regards

Mark

Link to comment
Share on other sites

Here is my commented pseudo-code for getting the token.  I'll post the code for the callback separately.
Please feel free to peer-review and make suggestions for improvement.

        private static string GetOAuthToken()
        {
            User currentUser = new <persisted user data >;

            // if the token has not expired, use it
            if (currentUser.SageAccessTokenExpiry != DateTime.MinValue && currentUser.SageAccessTokenExpiry > DateTime.UtcNow)
            {
                return currentUser.SageAccessToken;
            }

            // if refresh token has not expired, get a new token
            if (currentUser.SageRefreshTokenExpiry != DateTime.MinValue && currentUser.SageRefreshTokenExpiry > DateTime.UtcNow)
            {

                RestClient client = new RestClient("https://oauth.accounting.sage.com/token");

                RestRequest request = new RestRequest(Method.POST);

                request.AddObject(new
                {
                    client_id = < your SageClientId >,
                    client_secret = < your SageClientSecret >,
                    refresh_token = currentUser.SageRefreshToken,
                    redirect_uri = < your SageCallbackUrl >,
                    grant_type = "refresh_token"
                });

                IRestResponse response = client.Execute(request);

                if (response.ErrorException != null)
                {
                    throw response.ErrorException;
                }

                if (response.StatusCode.ToString() != "OK")
                {
                    if (!response.Content.Contains("refresh_token is invalid"))
                    {
                        throw new ApplicationException(response.Content);
                    }
                }
                else
                {
                    currentUser.SageAccessToken = Common.GetJsonValue(response.Content, "access_token");
                    currentUser.SageRefreshToken = Common.GetJsonValue(response.Content, "refresh_token");
                    long expires = long.Parse(Common.GetJsonValue(response.Content, "expires_in")); // seconds
                    currentUser.SageAccessTokenExpiry = DateTime.UtcNow.AddSeconds(expires);
                    long refreshExpires = long.Parse(Common.GetJsonValue(response.Content, "refresh_token_expires_in")); // seconds
                    currentUser.SageRefreshTokenExpiry = DateTime.UtcNow.AddSeconds(refreshExpires);
                    currentUser.Save();

                    return currentUser.SageAccessToken;
                }
            }

            // otherwise, start the process by requesting a new code

            HttpContext.Current.Session["SageRequestUrl"] = HttpContext.Current.Request.Url;
            string url = string.Format("https://www.sageone.com/oauth2/auth/central?filter=apiv3.1&response_type=code&client_id={0}&redirect_uri={1}&scope=full_access", Common.SageClientId, Common.SageCallbackUrl);
            HttpContext.Current.Response.Redirect(url);
            return string.Empty;
        }
 

  • Like 1
Link to comment
Share on other sites

Here is my commented pseudo-code for the callback.
Please feel free to peer-review and make suggestions for improvement.

    public partial class SageCallback : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.Params["code"] == null)
            {
                Response.Redirect("Default.aspx?Message=Missing [code] parameter in sage callback request.");
            }

            RestClient client = new RestClient("https://oauth.accounting.sage.com/token");

            RestRequest request = new RestRequest(Method.POST);

            request.AddObject(new
            {
                code = Request.Params["code"],
                client_id = < your SageClientId >,
                client_secret = < your SageClientSecret >,
                redirect_uri = < your SageCallbackUrl >,
                grant_type = "authorization_code"
            });

            IRestResponse response = client.Execute(request);

            if (response.ErrorException != null)
            {
                Response.Redirect("Default.aspx?Message=" + response.ErrorException.Message);
            }

            if (response.StatusCode.ToString() != "OK")
            {
                Response.Redirect("Default.aspx?Message=Unexpected error authenticating Sage");
            }

            User currentUser = < persisted user object >;
            currentUser.SageAccessToken = GetJsonValue(response.Content, "access_token");
            currentUser.SageRefreshToken = GetJsonValue(response.Content, "refresh_token");
            long expires = long.Parse(GetJsonValue(response.Content, "expires_in")); // seconds
            currentUser.SageAccessTokenExpiry = DateTime.UtcNow.AddSeconds(expires);
            long refreshExpires = long.Parse(GetJsonValue(response.Content, "refresh_token_expires_in")); // seconds
            currentUser.SageRefreshTokenExpiry = DateTime.UtcNow.AddSeconds(refreshExpires);
            currentUser.Save();

            string url = "Default.aspx?Message=Sage access granted.  Please retry Sage update request.";
            Response.Redirect(url);
        }
    }
 

  • Like 1
Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...