Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

This space is made available to users of Open Patent Services (OPS) web-service and now also to users of EPO’s bulk data subscription products such as 14. EPO worldwide bibliographic database (DOCDB), 14.11 EPO worldwide legal status database (INPADOC), 14.12 EP full text data, 14.1 EP bibliographic data (EBD)and more.

Users can ask each other questions, exchange experiences and solutions, post ideas. The moderator will use this space to announce changes or other relevant information.
Post Reply

jdargaud
Posts: 6
Joined: Wed Jan 09, 2019 9:32 am

Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by jdargaud » Wed Jan 09, 2019 9:51 am

Hi there,

I am trying to put up a request on OPS V3.2 from a javascript application running in my browser (firefox).
I send a first request using the fetch API :

Code: Select all

fetch('https://ops.epo.org/3.2/auth/accesstoken',
  {
    method: 'POST',
    headers:{
      'content-type': 'application/x-www-form-urlencoded',
      'Authorization': 'Basic ' + window.btoa(userkey+':'+secretkey)
    },
    body: 'grant_type=client_credentials'
  }
)
which works fine, I get in a code 200 answer with an access_token :D .
However, when I try next to send a POST request using the same method

Code: Select all

fetch('https://ops.epo.org/3.2/rest-services/published-data/{publication}/{epodoc}/biblio',
  {
    method: 'POST',
    headers:{
      'Accept': 'application/exchange+xml',
      'Authorization': 'Bearer '+ token
    },
    body: 'EP1000000.A1'
  }
)
where token is the access_token obtained before,
I get the 403 code error with X-Rejection-Reason:AnonymousQuotaPerDay on the "pre-flight" request, i. e. when firefox tests whether the server is cross-domain compliant. Obviously, I get afterwards a networking error stating that my request does not satisfy the cross-domain policy and Firefox does not send the main request.

I get the feeling that my credentials are ok, since in the first request, I can see my email adress in the answer body (under developer.email). Then why would I be treated as anonymous?

Can anyone shed some light here ? That would be most appreciated.
Best regards,

JB Dargaud
Last edited by jdargaud on Thu Jan 10, 2019 8:27 am, edited 1 time in total.


EPO / OPS Support
Posts: 1294
Joined: Thu Feb 22, 2007 5:32 pm

Re: Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by EPO / OPS Support » Wed Jan 09, 2019 1:53 pm

Hi,

Your POST request seems incorrect and it seems you are not using your token in that request at all, this is why you are getting this anonymous access error.

If you want to test POST, use Developers testing console

Regards,
Vesna for OPS support


jdargaud
Posts: 6
Joined: Wed Jan 09, 2019 9:32 am

Re: Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by jdargaud » Wed Jan 09, 2019 4:12 pm

Hi there,

I do use the token in the second POST

Code: Select all

'Authorization': 'Bearer '+ token
where token is a variable whose value is the access_token.
A console log just before the request confirms this.

I managed some minutes ago to get the document, however I do not know how, I know went back to the same error message.
I tried with postman, where it works OK. I even used postman to get the token and put it hard coded in my script, to no avail. I suspect somethig is wrong with my fetch request, but I do not see what.
Maybe the application header ?
Also, I do not understand how I pass the payload of the request : a simple string in the body ?

When I will get this running, I will post a minimal working exemple to serve other users who wants to implement OPS in a javascript application.


jdargaud
Posts: 6
Joined: Wed Jan 09, 2019 9:32 am

Re: Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by jdargaud » Fri Jan 11, 2019 11:15 am

The plot thickens...
When I try on my computer at home, I manage to fetch whatever I want. However on my computer at work, it fails with the same code.
Headers sent are identical except for the firefox version used: 60 at work and 64 at home.
To resume :

Code: Select all

function userAction ()
{
    //get access token for registration
    fetch('https://ops.epo.org/3.2/auth/accesstoken',
	  {
	      method: 'POST',
	      headers:{
		  'Content-Type': 'application/x-www-form-urlencoded',
		  'Authorization': 'Basic ' + window.btoa("appKey:secretKey")
	      },
	      body: 'grant_type=client_credentials'
	  }
	 )
	.then( //authentication fetch.then
	    (resp) => resp.json())
	.then( // json.then
	    function (data){
			getData(data.access_token);//Now that I have a token, I can send the real request
	    }
	)
    .catch(//authentication fetch.catch
	    function (error){
			console.log('error1'+error);
	    }
	)
}
And then, upon succeding in obtaining a valid token, I send the GET request:

Code: Select all

function getData(token){
    console.log('success in getting access token: '+ token);
    // true call
    fetch('https://ops.epo.org/3.2/rest-services/published-data/publication/epodoc/EP10000000.A1/biblio',
	  {
	      method: 'GET',
	      headers:{
			'Authorization': 'Bearer '+ token
	      }
	  }
	 )
	.then( //fetch 2.then
	    (resp2) => resp2.text()
		.then( //text 2.then
		    function (data){
			console.log(data);
		    }
		)
		.catch( //text 2.catch
		    function (error){
			console.log(error);
		    }
		)
	)
	.catch( //fetch 2.catch
	    function (error){
		console.log('fetch error '+error);
	    }
	)
}
For the first request, the pre-flight header is

Code: Select all

https://ops.epo.org/3.2/auth/accesstoken
Host: ops.epo.org
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,fr;q=0.8,fr-FR;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization
Origin: null
Connection: keep-alive
For the second, it is:

Code: Select all

https://ops.epo.org/3.2/rest-services/published-data/publication/epodoc/EP10000000.A1/biblio
Host: ops.epo.org
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,fr;q=0.8,fr-FR;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Origin: null
Connection: keep-alive
The only difference is that one is a POST and the other one is a GET. Both works prefectly fine with POSTMAN or the API console...
Does anyone have a insightful idea of what may cause this problem? Maybe a firewall or something?


jdargaud
Posts: 6
Joined: Wed Jan 09, 2019 9:32 am

Re: Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by jdargaud » Mon Feb 04, 2019 2:20 pm

Hi there,
I searched a little but further and now here are my symptoms: the same snippet either works or not due to external circumstances...
Below is a minimal working exemple. It is a simple html page with a button. When clicking on it, it executes embedded javascript code with fetch API.

Code: Select all

<!DOCTYPE html>
<head>
</head>
<body>
	<div>
		<button value="toto" onClick="userAction()">Mon gros bouton</button>
	</div>
	<script>
    /* javascript */
function userAction ()
{
	// ID et Pwd
	var myID = myID';
	var myPwd = 'password';
	
	var appNumber = "EP1000000A1";
       //get access token for registration
		fetch('https://ops.epo.org/3.2/auth/accesstoken',
		{
			method: 'POST',
			headers:{
			'Accept' : 'application/json',
			'Content-Type': 'application/x-www-form-urlencoded',
			'Authorization': 'Basic ' + window.btoa(myID+':'+myPwd)
			},
			body: 'grant_type=client_credentials'
		}
		)
		.then( //authentication fetch.then
			(resp) => resp.json())
		.then( // json.then
	    function (data){
			getData(data.access_token, appNumber);
			return;
	    }
	)
    .catch(//authentication fetch.catch
	    function (error){
			console.log('error '+error);
			alert("Hum...");
	    }
	)
}

function getData(token, application){
    console.log('success in getting access token: '+ token);
    // true call
    fetch('https://ops.epo.org/3.2/rest-services/published-data/publication/epodoc/biblio',
	  {
	      method: 'POST',
	      headers:{
			'Content-Type': 'text/plain',
			'Authorization': 'Bearer '+ token
	      },
		  body: application
	  }
	 )
	.then( //fetch 2.then
	    (resp2) => resp2.text())
	.then(
		function (data){
		\\do something with your data
		}
	)
	.catch( //text 2.catch
	    function (error){
		console.log(error);
	    }
	)
}
/* #javascript */
	</script>
</body>
</html>
Sometimes it works OK, sometimes it simply doesn't.
The preflight request of the second fetch XHTTP request does not comply with CORS policy. And the error message suggests that I am not authenticated. However, as it is a pre-flight request, one should not be authenticated, since one only wants to know whether cross domain request are allowed.
Below is the answer header with the 403 error code.

Code: Select all

HTTP/1.1 403 Forbidden
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: *
Content-Type: application/xml
Date: Mon, 04 Feb 2019 12:50:53 GMT
X-EPO-Client-IP: ***********
X-EPO-Forwarded: ***********
X-Rejection-Reason: AnonymousQuotaPerDay
Content-Length: 207
Connection: keep-alive
I found out that there were users of OPS with the same IP but a different acocunt (they are from a different company). I wonder if there are any limitations to the number of users per day on the same IP ?
And if I use their credentials, the code still fails...

I am at a loss. Please anybody?


EPO / OPS Support
Posts: 1294
Joined: Thu Feb 22, 2007 5:32 pm

Re: Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by EPO / OPS Support » Tue Feb 05, 2019 11:29 am

Hi,

I don't think that other users would result into you getting anonymous quota per day error. You would get error that your daily or hourly quota is reached if more users would be taking too much data. Also, there is a consumption app that you can use in OPS (see OPS documentation). OPS is also not set on a level of IP, this would be the case for “manual” users in Espacenet, but not in OPS.

Maybe a fellow user of OPS reading this would be able to suggest how to avoid issues that you experience when working from your office.

ANY IDEA ANYONE??

Regards
Vesna for OPS forum


mjcrcastro
Posts: 1
Joined: Fri Jul 15, 2022 8:32 pm

Re: Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by mjcrcastro » Fri Jul 15, 2022 8:42 pm

For those finding these questions after having a similar problem, you could be running into CORS issues. The origin of the original post problem is likely because of trying to use javascript on a first server (the development server) which is trying to get data from a second server (the EPO server) which Chrome (in my case) identifies as "Cross-Origin Resource Sharing" and blocks by default. Because the browser does a prefetch (no idea why) but does not include user data (e.g., the token) with the prefetch, the EPO server sees a non-authenticated user trying to get access to protected data. Playing nice, the EPO server provides data as long as the request is not abusive (will only serve so many anonymous requests before refusing to provide more data).

The behavior you see is that sometimes you get access to data (during the first times the EPO server provides non-authenticated data) then the EPO server denies further access. The amount of data available to anonymous users is reset periodically it seems because the EPO will provide data again after a certain time.

How to fix it? In my case, I solved it using a HtmlClient built within laravel, the framework I use. I have no idea how to do it using Javascript only.

Hope this helps.
Last edited by mjcrcastro on Fri Jul 15, 2022 8:46 pm, edited 1 time in total.


EPO / OPS Support
Posts: 1294
Joined: Thu Feb 22, 2007 5:32 pm

Re: Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by EPO / OPS Support » Thu Sep 01, 2022 10:09 am

Hi,

The post you have replied to was from 2019, but since then we completely closed anonymous access to OPS. In 2019, we had 3 options to access data: anonymous, free of charge registered option to up to 2,5 GB and paying registered option. Since then only free of charged registered option up to 4 GB and paying register option is still available.

Regards,
Vesna for OPS support


PAFB
Posts: 1
Joined: Wed Feb 01, 2023 9:56 pm

Re: Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by PAFB » Wed Feb 01, 2023 10:45 pm

Hi,

I have the same problem as is described in the original post. This problem results from the fact that all common web browsers apply the CORS system. According to https://developer.mozilla.org/en-US/docs/Glossary/CORS:
CORS (Cross-Origin Resource Sharing) is a system, consisting of transmitting HTTP headers, that determines whether browsers block frontend JavaScript code from accessing responses for cross-origin requests.

The same-origin security policy forbids cross-origin access to resources. But CORS gives web servers the ability to say they want to opt into allowing cross-origin access to their resources.
Due to the CORS system, if some javascript code hosted on a first server tries to load data from a second server the web browser does not directly executes this cross-origin request, but first sends a preflight request to the second server. According to https://developer.mozilla.org/en-US/doc ... ht_request:
A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers.

It is an OPTIONS request, using three HTTP request headers: Access-Control-Request-Method, Access-Control-Request-Headers, and the Origin header.
This preflight request is automatically created and sent by the web browser to the cross-origin server. It contains only the three headers mentioned in the quote and particularly never contains any authorization header. In fact, sending authorization headers with the preflight request would not make any sense, since the preflight request only serves to determine whether cross-origin access is generally allowed, but not to actually access any data. This is why a server should always respond to a preflight request with headers only, but with no content in the body, and why the HTTP response status code should always be "204 (No Content)".

The OPS servers, however, respond to the preflight request with a status code of "403 (Forbidden)". Apparently, the OPS servers are expecting authorization credentials even for the preflight request, but authorization credentials are never sent in a preflight request (and could not even be added if one wanted to, since the preflight request is automatically generated by the web browser and cannot be modified). Responding with a status code of "403 (Forbidden)" to a preflight request does not make any sense and is not in accordance with how CORS works. This completely and inevitably blocks any access to OPS data from client-side javascript code, i.e. from javascript code that is executed as part of a web page by a web browser. I assume that this cannot be intentional.

Therefore, in my opinion, the OPS servers are not properly configured for CORS requests.

Could you please have a further look into this and, ideally, fix how the OPS severs handle CORS.

Best regards,


cahe
Posts: 1
Joined: Tue Feb 28, 2023 1:16 pm

Re: Javascript with fetch API : Error403 with X-Rejection-Reason:AnonymousQuotaPerDay

Post by cahe » Tue Feb 28, 2023 2:12 pm

I agree @PAFB -- it could not possibly be correct on the server side.

I have an identical situation, but using C#.
I have no issue getting a bearer token:

Code: Select all

        using (var client = new HttpClient())
        {
            string baseAddress = @"https://ops.epo.org/3.2/auth/accesstoken";


            client.DefaultRequestHeaders.Add("Authorization", $"Basic {bearerToken}");
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));


            // These headers should not be needed but I added them in trying to see where I could be going wrong.
            // They won't break anything
            client.DefaultRequestHeaders.Add("User-Agent", "PostmanRuntime/7.30.0"); 
            client.DefaultRequestHeaders.Add("Accept", "*/*");
            client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
            client.DefaultRequestHeaders.Add("Connection", "keep-alive");

            
            
            var form = new Dictionary<string, string>
                {
                    { "grant_type", "client_credentials" }
                };


            HttpResponseMessage tokenResponse = await client.PostAsync(baseAddress, new FormUrlEncodedContent(form));

            var headers = tokenResponse.Headers;

            foreach (var header in headers)
            {
                Console.WriteLine($"{header.Key} = {header.Value.FirstOrDefault()}");
            }

            var jsonContent = await tokenResponse.Content.ReadAsStringAsync();
            var tok = JsonConvert.DeserializeObject<Token>(jsonContent);

            return tok; // SUCCESS -- THE Reponse has the token object at this point
        }
        
Then I try to apply that access token in the header...
If it was a raw header it would be like "Authorization: Bearer ABDEFGHhijklmnoPqRsTUvWxYz123"

Code: Select all

        using (var client = new HttpClient())
        {
            string baseAddress = $"https://ops.epo.org/rest-services/published-data/publication/epodoc/EP1000000";

            client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

            // These won't make any difference... but trying to diagnose the issue
            client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
            client.DefaultRequestHeaders.Add("Connection", "keep-alive");
            client.DefaultRequestHeaders.Add("Accept", "*/*");

            // Adding this to see if it makes any difference
            client.DefaultRequestHeaders.Add("User-Agent", "PostmanRuntime/7.30.0"); 
            
            
            using HttpResponseMessage response = client.GetAsync(baseAddress).Result;

            // Trying to see why I keep getting 403 here. The X-Rejection-Reason is always set to "AnonymousQuotaPerDay",
            // which is incorrect, as the Authorization Header is set to Bearer + accessToken.
            var headers = response.Headers;

            foreach (var header in headers)
            {
                Console.WriteLine($"{header.Key} = {header.Value.FirstOrDefault()}");
            }

            response.EnsureSuccessStatusCode();

            var jsonContent = response.Content.ReadAsStringAsync().Result;

            return jsonContent;
        }
        

There is a header in the 403 response...
X-Rejection-Reason = AnonymousQuotaPerDay

I can reproduce the exact same response if I remove the Authorization header....
So, removing this line:

client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);


... makes no difference. Response and headers are the exact same.


Bizarrely, if I grab the accessToken from my first code block to get the token, and apply it in Postman, I have no issue getting a reply.

So there has to be something over-zealous going on in the code, I imagine the developers are trying to stop abuse of the API so some super-validation is going on, so good that it in fact is stopping perfectly OK API calls.


Post Reply