Does the client need to wait after a successful login?

The documentation for the Login method says:

If response code is 401 Unathorized stop sending further requests with the same credentials, login is “expensive” operation.

Request rate limit is 1 request per 1 second.

Side note: Unathorized should be: Unauthorized
Side note: login is “expensive” operation should be: login is an “expensive” operation

Makes sense that the server rate limits failing login requests. However upon successful login the server is returning:

ratelimit-reset: 1
ratelimit-remaining: 0
ratelimit-limit: 1

That indicates the request quota in the current time window has been used up and the client must wait one second before making another request.

Is this intended? Do clients have to wait after a successful login before sending a subtitle search request?

Full output from login test:
low-batt@gag ~$ curl -vvv --location '' \
>   --header 'Accept: */*' \
>   --header 'Content-Type: application/json' \
>   --header 'Api-Key: <REDACTED>' \
>   --user-agent '<REDACTED>' \
>   --data '{"username": "<REDACTED>", "password": "<REDACTED>"}'
*   Trying
* Connected to ( port 443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject:
*  start date: Oct  4 11:01:43 2023 GMT
*  expire date: Jan  2 11:01:42 2024 GMT
*  subjectAltName: host "" matched cert's "*"
*  issuer: C=US; O=Google Trust Services LLC; CN=GTS CA 1P5
*  SSL certificate verify ok.
* using HTTP/2
* h2 [:method: POST]
* h2 [:scheme: https]
* h2 [:authority:]
* h2 [:path: /api/v1/login]
* h2 [user-agent: <REDACTED>]
* h2 [accept: */*]
* h2 [content-type: application/json]
* h2 [api-key: <REDACTED>]
* h2 [content-length: 60]
* Using Stream ID: 1 (easy handle 0x121011400)
> POST /api/v1/login HTTP/2
> Host:
> User-Agent: <REDACTED>
> Accept: */*
> Content-Type: application/json
> Api-Key: <REDACTED>
> Content-Length: 60
* We are completely uploaded and fine
< HTTP/2 200 
< date: Thu, 05 Oct 2023 18:51:08 GMT
< content-type: application/json; charset=utf-8
< content-length: 315
< x-ratelimit-remaining-hour: 59
< x-ratelimit-limit-hour: 60
< ratelimit-reset: 1
< ratelimit-remaining: 0
< ratelimit-limit: 1
< x-ratelimit-remaining-second: 0
< x-ratelimit-limit-second: 1
< x-frame-options: SAMEORIGIN
< x-xss-protection: 1; mode=block
< x-content-type-options: nosniff
< x-download-options: noopen
< x-permitted-cross-domain-policies: none
< referrer-policy: strict-origin-when-cross-origin
< cache-control: max-age=0, private, must-revalidate, s-maxage=600
< access-control-allow-origin: *
< access-control-allow-methods: GET, HEAD, POST, OPTIONS
< access-control-allow-headers: Origin, Authorization, Accept, Api-Key, Content-Type, X-User-Agent
< content-security-policy: default-src 'self'; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'self'; form-action 'self' localhost:4200; frame-src 'self' * *; connect-src 'self' * rb-dev:8082 * wss://* *; base-uri 'self' *; frame-ancestors 'self'; script-src 'self' * https: 'unsafe-inline' 'unsafe-eval'; style-src 'self' https: 'unsafe-inline'
< x-request-id: 990fe2b5-2fc5-4872-990b-9137cadb4a19
< x-runtime: 0.425481
< x-stackifyid: V1|c62650a5-81f6-4fa6-ae94-d89e16d52e74|C98184|CD5
< x-kong-upstream-latency: 2863
< x-kong-proxy-latency: 3
< x-cache-backend: apigw1_8000 rb1
< age: 0
< x-var-cache: MISS
< x-via: fw1
< accept-ranges: bytes
< cf-cache-status: DYNAMIC
< report-to: {"endpoints":[{"url":"https:\/\/\/report\/v3?s=MsnFXf3kp2bxAJQrGWiIwuQtKHmTYTaoEjN6E%2B%2Fs2NoNqa0pc7uIa5LKVLx56qk1EE2mLW1jd79aGiupaSh40UtIHwD3VebAXaospi4cPXIAz4xsoKgHCX%2BSjszYYwjwqmoQ3dh%2FhZo%3D"}],"group":"cf-nel","max_age":604800}
< nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
< strict-transport-security: max-age=15552000; includeSubDomains; preload
< server: cloudflare
< cf-ray: 8117daa1eb128cda-EWR
< alt-svc: h3=":443"; ma=86400
* Connection #0 to host left intact
{"user":{"allowed_translations":1,"allowed_downloads":20,"level":"Sub leecher","user_id":<REDACTED>,"ext_installed":false,"vip":false},"token":"<REDACTED>","status":200}
low-batt@gag ~$ 

no, the 1req/1sec limiting only applies to the login

That is the answer I expected, but I didn’t want to ignore the rate limiting without getting an ok from you that it is fine to proceed immediately with the next request after a successful login.

I see this as a problem with the draft specification RateLimit header fields for HTTP, which under The following features are out of the scope of this document: says:

Throttling scope: This specification does not cover the throttling scope, that may be the given resource-target, its parent path or the whole Origin (see Section 7 of [WEB-ORIGIN]). This can be addressed using extensibility mechanisms such as the parameter registry Section 8.1.

The specification allows rate limiting to be applied to a specific resource, but fails to specify a standard way to communicate this to the client. Under Why don’t pass the throttling scope as a parameter? in the FAQ section there is some discussion as to why. Hopefully they will come up with some standard way for servers to communicate this to clients.

I had trouble posting this reply. I kept encountering “Error 503 Backend fetch failed” and “502 Bad Gateway”.

allright, that’s a little overkill for us to investigate, but if you can point details like this and give us the references we’ll do all we can to comply.

for the 503 and 502, I get them too, thanks for your patience, still couldn’t figure out why they occur

No need to investigate. My post above was to let you know I investigated this and to document what I found out. As the standard does not currently define a way to specify scope and as of now only one REST API method is “special”, I would not change anything at this time.

I would keep an eye on the progress of the standard and if the draft is updated with a header that defines the scope of the rate limit then consider including that header.