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

[BUG] APIRequestContext not honoring httpCredentials option #16005

Closed
rmunn opened this issue Jul 28, 2022 · 8 comments
Closed

[BUG] APIRequestContext not honoring httpCredentials option #16005

rmunn opened this issue Jul 28, 2022 · 8 comments

Comments

@rmunn
Copy link

rmunn commented Jul 28, 2022

Related to #13772; I believe this is the same issue, and that the repro in this issue will solve #13772 as well. When a new browser context is created with the httpCredentials option, context.request.get (and post and the other methods too, though this repro only demonstrates get) is not sending an Authorization header. The httpCredentials option appears to be ignored; if you want to use HTTP basic auth with an APIRequestContext, you have to create the Authorization header yourself.

Context:

  • Playwright Version: 1.24.1
  • Operating System: Linux
  • Node.js version: 16.14.0
  • Browser: N/A (bug is about APIRequestContext)
  • Extra: Nothing special

Code Snippet

First, clone https://github.com/heymagurany/http-echo-service and inspect it to see that it's not going to do anything nefarious, then run it in one terminal window/tab with node service.js 8800. Then create and run the following Playwright test in another terminal:

import { test, expect } from '@playwright/test';

test('echo server', async ({ browser }) => {
  const credentialContext = await browser.newContext({ httpCredentials: {username: 'foo', password: 'bar'} });
  const credentialResult = await credentialContext.request.get('http://localhost:8800/with-credentials');
  expect(credentialResult.status()).toBe(200);
  const manualAuthContext = await browser.newContext();
  const auth = Buffer.from('foo:bar').toString('base64');
  const authHeader = `Basic ${auth}`;
  const headers = { 'Authorization': authHeader }
  const manualAuthResult  = await manualAuthContext.request.get('http://localhost:8800/manual-header', {headers});
  expect(manualAuthResult.status()).toBe(200);
});

Look at the first terminal and the resulting output from the HTTP echo server. When I ran it, I got the following:

GET /with-credentials HTTP/1.1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.48 Safari/537.36
accept: */*
accept-encoding: gzip,deflate,br
host: localhost:8800
connection: close


GET /manual-header HTTP/1.1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.48 Safari/537.36
accept: */*
accept-encoding: gzip,deflate,br
authorization: Basic Zm9vOmJhcg==
host: localhost:8800
connection: close

Describe the bug

As you can see from the HTTP echo server's output, the request being sent out isn't adding an authorization: Basic header even though the context was created with the httpCredentials option. I believe from my look through the Playwright code that that option is being honored in actual browsers, but it's completely ignored in APIRequestContext methods. When I create the Authorization header myself (the second request), then it works and the request gets sent out with the HTTP basic auth header that I intended.

@rmunn
Copy link
Author

rmunn commented Jul 28, 2022

This may also be the cause of the issue mentioned in https://stackoverflow.com/questions/73069593/playwright-basic-authentication-for-api-test.

@mxschmitt
Copy link
Member

Relates #14067

@mxschmitt
Copy link
Member

Which response status does your backend return? Since not returning 401 when basic auth is used, means also that the browser would not show the basic auth dialog.

Thats a workaround in the meantime, to send the header just always:

const username = 'John';
const password = 'Doe';
const options = {
  headers: {
    'Authorization': `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`
  },
};
request.get('http://localhost:8800/manual-header', {headers});

@rmunn
Copy link
Author

rmunn commented Aug 2, 2022

The backend returns 401 if no authorization header was included, 403 if an authorization header was included but has incorrect credentials (wrong password, or right password but that user isn't allowed to access that resource), and 200 if the auth header was included and was valid (right password and that user is allowed to access that resource).

@oscarm081297
Copy link

Which response status does your backend return? Since not returning 401 when basic auth is used, means also that the browser would not show the basic auth dialog.

Thats a workaround in the meantime, to send the header just always:

const username = 'John';
const password = 'Doe';
const options = {
  headers: {
    'Authorization': `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`
  },
};
request.get('http://localhost:8800/manual-header', {headers});

That works fine for basic auth, but looks like there is no way to make Digest auth work

@redReno
Copy link

redReno commented Dec 18, 2023

I can load my pages (which require digest authorization) but even if I reuse the context when using POST or GET the requests fail. This is a blocker for us, unfortunately.

@pavelfeldman
Copy link
Member

Why was this issue closed?

Thank you for your contribution to our project. This issue has been closed due to its limited upvotes and recent activity, and insufficient feedback for us to effectively act upon. Our priority is to focus on bugs that reflect higher user engagement and have actionable feedback, to ensure our bug database stays manageable.

Should you feel this closure was in error, please create a new issue and reference this one. We're open to revisiting it given increased support or additional clarity. Your understanding and cooperation are greatly appreciated.

@rmunn
Copy link
Author

rmunn commented Apr 25, 2024

I've tested it, and Playwright is sending the httpCredentials if the server correctly replies with a 401. However, not all servers do that, so it would be nice to be able to ask for the credentials to be sent on the first request. So I've opened a feature request for that: #30534.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants