Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Option to always send httpCredentials in APIRequestContext #30534

Closed
rmunn opened this issue Apr 25, 2024 · 3 comments · Fixed by #30627
Closed

[Feature]: Option to always send httpCredentials in APIRequestContext #30534

rmunn opened this issue Apr 25, 2024 · 3 comments · Fixed by #30627
Assignees
Labels

Comments

@rmunn
Copy link

rmunn commented Apr 25, 2024

🚀 Feature Request

The httpCredendtials feature on APIRequestContext works by lookiing for an HTTP 401 response and sending the credentials only if the 401 response contains a WWW-Authenticate header. (And then, only if the header starts with "Basic" — digest authentication is apparently not supported yet).

For most servers, this works fine. But there are some servers out there that do not send a 401 when a request lacks authentication, but instead send a 403 or other response. The HTTP/1.1 spec, RFC 7235, states (on page 4, you may need to scroll down) that servers SHOULD send a 401 when a request lacks credentials, but SHOULD is not MUST and not all servers choose to send a 401.

Upon receipt of a request for a protected resource that omits credentials, contains invalid credentials (e.g., a bad password) or partial credentials (e.g., when the authentication scheme requires more than one round trip), an origin server SHOULD send a 401 (Unauthorized) response that contains a WWW-Authenticate header field with at least one (possibly new) challenge applicable to the requested resource.

In order to make it easier to send authenticated GET requests to servers that don't send 401 errors, it would be nice to have an option in the httpCredentials object called alwaysSendCredentials or perhaps just always for short. This would send the Authorization: Basic Zm9vOmJhcg== header on the first request, rather than waiting for a 401 and sending a second request with the header. If the optional origin property was given, then always would add the credentials only to requests going to that origin.

Example

const authContext = await browser.newContext({
    httpCredentials: {
        username: 'foo',
        password: 'bar',
        origin: 'http://localhost:4173',
        always: true,
}});
await authContext.request.get('http://localhost:4173/protected'); // Sends credentials on first request

Motivation

Some people are dealing with servers that expect Authorization headers in the first request. Others are dealing with tests in a high-latency environment, where each HTTP request might take a second or two to receive a response. If each authenticated request has to be sent twice, that can add up to a lot of unnecessarily-wasted time.

In the case of servers that expect an Authorization header the first time, that's not what the HTTP spec says they SHOULD do... but SHOULD is not MUST, and a server that does not send 401 is still in compliance with the spec. It would be nice if httpCredentials could be easily used to send requests to such servers.

In the case of high-latency environments, being able to tell Playwright to always send credentials no matter what would result in tests that run faster.

In both cases, you can work around this by adding an Authorization header to extraHTTPHeaders so that it will be sent every time, but this is not always desirable as some requests might be going to servers (say, GitHub) where you don't want to send the credentials for your private API service. So having the always: true option available on httpCredentials and having it honor origin would be the best solution to both of these use cases.

@pavelfeldman
Copy link
Member

Do you know if other API testing frameworks do that? Having a list of frameworks would help as we would treat it as feature parity.

@rmunn
Copy link
Author

rmunn commented Apr 26, 2024

Can't claim to know all the API testing frameworks, so I have likely missed some (maybe including some that are in common use), but here's what some of them do:

  • pactum has a withAuth helper. I tested and confirmed that it sends the Authorization header on the first request, without waiting to receive a 401.
  • supertest uses superagent under the hood; I confirmed that when you call superagent.get('http://localhost:8001').auth('user', 'pass') it sends an Authorization header on the first request without waiting for a 401.
  • I didn't try autokin because I didn't want to have to learn a specialized DSL intended for non-developers; I just wanted to try Javascript frameworks. It looks like it sends the Authorization header on the first try; however, I did not test that. (But I did find the implementation: when its basicAuthentication(username, password) function is called, it immediately adds an Authorization header. So I doubt it's waiting for a 401.)
  • frisby doesn't have an auth helper. The main example in its setup docs is putting an Authorization header in the extra-headers parameters, so that it gets sent on every request. I confirmed that it sends the Authorization header on the first request, without waiting to receive a 401.

I could try more, but after four in a row behaving the same way, I stopped. It looks to me like the "send the headers immediately without waiting for a 401" behavior is the default; I didn't find any that followed Playwright's behavior of waiting for the 401. (It's remotely possible that I'm mistaken about what autokin does, as I didn't actually test it, only read the source code).

@hahn-kev
Copy link

hahn-kev commented Apr 26, 2024

Looking at Cypress their docs about api testing say options for auth are defined here, which has a parameter sendImmediately which is described as this:

sendImmediately defaults to true, which causes a basic or bearer authentication header to be sent. If sendImmediately is false, then request will retry with a proper authentication header after receiving a 401 response from the server (which must contain a WWW-Authenticate header indicating the required authentication method).

sounds like a good example to follow, obviously playwright should probably have sendImmediately default to false so as to not break existing code.

yury-s added a commit to yury-s/playwright that referenced this issue May 2, 2024
yury-s added a commit that referenced this issue May 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants