258

I want to write a simple basic authentication with fetch, but I keep getting a 401 error. It would be awesome if someone tells me what's wrong with the code:

let base64 = require('base-64');

let url = 'http://eu.httpbin.org/basic-auth/user/passwd';
let username = 'user';
let password = 'passwd';

let headers = new Headers();

//headers.append('Content-Type', 'text/json');
headers.append('Authorization', 'Basic' + base64.encode(username + ":" + password));

fetch(url, {method:'GET',
        headers: headers,
        //credentials: 'user:passwd'
       })
.then(response => response.json())
.then(json => console.log(json));
//.done();
Tobias Buschor
  • 3,075
  • 1
  • 22
  • 22
daniel.lozynski
  • 14,907
  • 6
  • 18
  • 21

9 Answers9

258

A solution without dependencies.

Node

headers.set('Authorization', 'Basic ' + Buffer.from(username + ":" + password).toString('base64'));

Browser

headers.set('Authorization', 'Basic ' + btoa(username + ":" + password));
qoomon
  • 4,549
  • 1
  • 21
  • 27
  • 10
    In a browser you can use ```window.btoa(username + ':' + password);``` https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding – Andreas Riedmüller Jan 08 '19 at 13:38
  • 2
    to support special characters something like ```window.btoa(unescape(encodeURIComponent(string)));``` should do the job, you can read more about this here: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem – Andreas Riedmüller Jan 08 '19 at 13:47
  • Also depending on your version of node `fetch` doesn't exist there. – dovidweisz Feb 08 '19 at 18:21
213

You are missing a space between Basic and the encoded username and password.

headers.set('Authorization', 'Basic ' + base64.encode(username + ":" + password));
Knu
  • 14,806
  • 5
  • 56
  • 89
Lukasz Wiktor
  • 19,644
  • 5
  • 69
  • 82
  • 13
    Isnt atob and btoa built in to the Javascript specification? – Martin Mar 12 '19 at 10:03
  • 9
    The 2 functions are available in all major browsers, but I don't think they are covered by any ES specification. In particular, you won't find them in node.js https://github.com/nodejs/node/issues/3462 – Lukasz Wiktor Mar 13 '19 at 15:00
  • Note that this does NOT establish a session for the browser. You can use XHR to both establish a session and avoid base64 encoding. See: https://stackoverflow.com/a/58627805/333296 – Nux Oct 30 '19 at 14:41
  • Uncaught ReferenceError: base64 is not defined – Sveen Feb 28 '20 at 21:15
  • 6
    @Sveen `base64` refers to the library imported in the original post. It is not a built-in global, but a library that was imported in the CJS module. – oligofren Apr 02 '20 at 12:12
  • 8
    When using node, you have to use Buffer and specify utf8 `const headers = { Authorization: \`Basic ${Buffer.from("user:pass", "utf-8").toString("base64")}\` }; ` – chilljul Sep 19 '21 at 08:24
  • 1
    Thank you so much. – Nguyễn Anh Tuấn Feb 09 '22 at 16:23
42

A simple example for copy-pasting into Chrome console:

fetch('https://example.com/path', {method:'GET', 
headers: {'Authorization': 'Basic ' + btoa('login:password')}})
.then(response => response.json())
.then(json => console.log(json));

or with await:

let response = await fetch('https://example.com/path', {method:'GET', 
headers: {'Authorization': 'Basic ' + btoa('login:password')}});
let data = await response.json();
console.log(data);
kolypto
  • 31,774
  • 17
  • 105
  • 99
40

In pure JavaScript you can also use btoa instead of base64.encode():

headers.set('Authorization', 'Basic ' + btoa(username + ":" + password));

Note that this will only work with ASCII characters.

If you have to handle different encodings, see the linked btoa documentation.

Valerio Bozz
  • 1,176
  • 16
  • 32
Ilya
  • 591
  • 5
  • 6
16

If you have a backend server asking for the Basic Auth credentials before the app then this is sufficient, it will re-use that then:

fetch(url, {
  credentials: 'include',
}).then(...);
OZZIE
  • 6,609
  • 7
  • 55
  • 59
14

NODE USERS (REACT,EXPRESS) FOLLOW THESE STEPS

  1. npm install base-64 --save
  2. import { encode } from "base-64";
  3.  const response = await fetch(URL, {
      method: 'post',
      headers: new Headers({
        'Authorization': 'Basic ' + encode(username + ":" + password),
        'Content-Type': 'application/json'
      }),
      body: JSON.stringify({
        "PassengerMobile": "xxxxxxxxxxxx",
        "Password": "xxxxxxx"
      })
    });
    const posts = await response.json();
    
  4. Don't forget to define this whole function as async

kumar kundan
  • 2,027
  • 1
  • 27
  • 41
4

get request with authorization for React Native Mobile application, i have spent more time searching for these lines inside fetch

 var base64 = require("base-64"); // install it before use from npm i base-64

 const uname = "some username goes here";
 const pword = "some password goes here";

const getMovies = async () => {
   try {
     const response = await fetch(
       "API URL goes here",
       {
         headers: {
           Authorization: "Basic " + base64.encode(uname + ":" + pword),
         },
       }
     );

     data = await response.json();
     setData(data);

     console.log(data);
     // console.log(data.name);
     return data;
   } catch (error) {
     console.error(error);
   } finally {
     setLoading(false);
   }
 };

 useEffect(() => {
   getMovies();
 }, []);


// other code 

// inside return
  <FlatList
           keyExtractor={(item) => item.id}
           data={data}
           renderItem={({ item }) => (
             <View style={styles.text_container}>
               <Text>{item.name}</Text>
               <Text>{item.images[0].name}</Text>
               <Text>{item.images[0].src}</Text>
             </View>
           )}
         />

fixedDrill
  • 183
  • 1
  • 13
3

I'll share a code which has Basic Auth Header form data request body,

let username = 'test-name';
let password = 'EbQZB37gbS2yEsfs';
let formdata = new FormData();
let headers = new Headers();


formdata.append('grant_type','password');
formdata.append('username','testname');
formdata.append('password','qawsedrf');

headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch('https://www.example.com/token.php', {
 method: 'POST',
 headers: headers,
 body: formdata
}).then((response) => response.json())
.then((responseJson) => {
 console.log(responseJson);

 this.setState({
    data: responseJson
 })
  })
   .catch((error) => {
 console.error(error);
   });
Manoj Perumarath
  • 9,337
  • 8
  • 56
  • 77
1

This is not directly related to the initial issue, but probably will help somebody.

I faced same issue when was trying to send similar request using domain account. So mine issue was in not escaped character in login name.

Bad example:

'ABC\username'

Good example:

'ABC\\username'
DJ-Glock
  • 1,277
  • 2
  • 12
  • 39
  • This is just because you need to escape js string escape character itself, however this is not basic auth related. – qoomon Jan 24 '20 at 11:06
  • @qoomon correct. That's why I mentioned that it is not directly related, but might be helpful. – DJ-Glock Jan 25 '20 at 12:02