Reginald Jackson Posted February 14, 2021 Posted February 14, 2021 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
Stuart Eastland Posted February 14, 2021 Posted February 14, 2021 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.
Stuart Eastland Posted February 15, 2021 Posted February 15, 2021 I found that my initial problem was the value I was supplying for scope was incorrect. I am now able to make the initial request and get a code returned, however when I send this back for a token I am getting a http 400 error. I'll compare my request string with the postman values...
Stuart Eastland Posted February 15, 2021 Posted February 15, 2021 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
Stuart Eastland Posted February 16, 2021 Posted February 16, 2021 I was not building my request correctly and I can now get the token back using my c# code. I found the sample code rather difficult to follow as I am an old school ASP Forms developer (no MVC or SPA) so I stripped it right down the the basic Request/Response mechanism and cut it down significantly.
Steel, Mark Posted February 18, 2021 Posted February 18, 2021 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
Reginald Jackson Posted February 19, 2021 Author Posted February 19, 2021 Hi, This turned out to be a syntax error on my part thanks.
Administrators Ben Smith Posted February 22, 2021 Administrators Posted February 22, 2021 Thanks for letting us know Reginald. Ben
Stuart Eastland Posted February 24, 2021 Posted February 24, 2021 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; } 1
Stuart Eastland Posted February 24, 2021 Posted February 24, 2021 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); } } 1
Recommended Posts
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now