Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
While I don't have a good answer for your question, I'd like to point out that creating HttpClient for each request is considered bad practice and should be avoided. Better to create one instance and reuse
Thanks Quan.
Do you think this might happen due to parallel requests using separate tokens over async call and might not get authorized? I'll try to make it into 1 call though to see if it works. In some random cases I get authorized and the call completes with appropriate token.
Could be. I'm not an Oauth expert (I should be), but it is possible that if you have parallel requests, the later token might invalidate the early one. It might also be a good idea to reuse the bearer token until it's expired (again, not an expert)
Thanks Quan. I'll give it a try. Though on my local environment I never had this problem. Do you have any example how to reuse the token?
It seems to have been resolved since I had the HttpClient instance at the constructor. That way it makes 1 instance of HttpClient and the authorize token (internally being generated within HttpClient).
Thanks Quan.
Hello Manoj
I'm working with the support case related this thread.
Is problem still persist?
In your local developement, did you setup with https?
At the moment, I don't have any idea but I suggest a solution:
When Job has error, we will retry one more time: re get token and re-post
Thanks Cuvu,
We've tried it earlier but the intermittent behavior is there. Could you please list out the must-have configuration settings on production? On local without/with https it works just fine.
Hello
You can find documentation here: https://world.episerver.com/documentation/developer-guides/Optimizely-Service-API/installation-and-configuration/
But I think it's not related configuration because as you said error occurs some points.
Could you change logic as I mentioned: when error occurs, job will retry one more time and log bug for that request?
Cuvu,
We have tried re-running the job iteration when it throws an exception while generating the token request. There is no full stack trace except the message 'User is not authorized for this request'
What do you think might be the reason behind this error?
@Manoj can we see what authentication options you've setup on the Service API side?
I'm using EPIServer Service APIs to import products/catalog from xml file through a scheduled job.
The version is close/latest to the version I'm using in my project. https://world.episerver.com/documentation/class-libraries/rest-apis/service-api/
<package id="EPiServer.ServiceApi" version="5.4.5" targetFramework="net47" /> <package id="EPiServer.ServiceApi.Commerce" version="5.4.5" targetFramework="net47" />
And the commerce version is
<package id="EPiServer.Commerce" version="13.12.0" targetFramework="net47" />
Implementation
I've got a scheduled job that reads an XML through asset pane and imports the entries / catalog from that file. This file is using Service APIs to import an entry and it's associations with following code base, in following order -
import the entries -
var result = Post("/episerverapi/commerce/entries", new StringContent(json, Encoding.UTF8, "application/json"));
Import the prices -
var pricePostMultiple = Post($"/episerverapi/commerce/entries/{entry.Code}/prices/multiple", new StringContent(JsonConvert.SerializeObject(priceList), Encoding.UTF8, "application/json")).Result;
Node entry relations -
var nodeEntryRelations = Post( $"/episerverapi/commerce/entries/{entry.Code}/nodeentryrelations", new StringContent(entryRelation, Encoding.UTF8, "application/json"));
Catalog Association -
var entryAssociation = Post($"/episerverapi/commerce/entries/{entry.Code}/associations", new StringContent(entryRelation, Encoding.UTF8, "application/json"));
Issue
We've been getting intermittent response from the prod server where the each of above APIs would fail at some point with the response "User is not authorized for this request". Though the user which this API client is using exists with all the required credentials and has enough permissions for functions to read/write the catalog.
The API is making connection to the Service API through OAuth2Client. Here is the complete file -
public abstract class BaseActor { public abstract string Execute(); private readonly string _baseUrl; private readonly OAuth2Client _oAuth2Client; /// <summary> /// Initializes a new instance of the <see cref="BaseActor"/> class. /// </summary> protected BaseActor() { _baseUrl = SiteDefinition.Current.SiteUrl.AbsoluteUri; _oAuth2Client = new OAuth2Client(new Uri(_baseUrl + "episerverapi/token")); } private async Task<HttpClient> GetHttpClient() { try { var userName = ConfigurationManager.AppSettings["username"]; var password = ConfigurationManager.AppSettings["password"]; var token = await _oAuth2Client.RequestResourceOwnerPasswordAsync(userName, password); if (token.IsError) { return null; } var client = new HttpClient() { BaseAddress = new Uri(_baseUrl) }; client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken); return client; } catch (Exception e) { Console.WriteLine(e); throw; } } /// <summary> /// Posts the specified URL. /// </summary> /// <param name="url">The URL.</param> /// <param name="content">The content.</param> /// <returns></returns> protected async Task<HttpResponseMessage> Post(string url, HttpContent content) { var client = await GetHttpClient(); return client?.PostAsync(url, content).Result; } /// <summary> /// Puts the specified URL. /// </summary> /// <param name="url">The URL.</param> /// <param name="content">The content.</param> /// <returns></returns> protected async Task<HttpResponseMessage> Put(string url, HttpContent content) { var client = await GetHttpClient(); return client?.PutAsync(url, content).Result; } /// <summary> /// Gets the specified URL. /// </summary> /// <param name="url">The URL.</param> /// <returns></returns> protected async Task<HttpResponseMessage> Get(string url) { var client = await GetHttpClient(); return client?.GetAsync(url).Result; } /// <summary> /// Gets the specified URL. /// </summary> /// <param name="url">The URL.</param> /// <param name="completionOption">The completion option.</param> /// <returns></returns> protected async Task<HttpResponseMessage> Get(string url, HttpCompletionOption completionOption) { var client = await GetHttpClient(); return client?.GetAsync(url, completionOption).Result; } /// <summary> /// Puts the specified URL. /// </summary> /// <param name="url">The URL.</param> /// <returns></returns> protected async Task<HttpResponseMessage> Delete(string url) { var client = await GetHttpClient(); return client?.DeleteAsync(url).GetAwaiter().GetResult(); } }
The issue is only occuring at production which is on-premise. Does it have to do anything with the permissions those need to be allowed? I've no clue why this is failing or even where to look for if this is a permission issue.
Thanks for your help.