How to do Basic Auth with Axios in react - reactjs

React Code
import React, { useState, useEffect } from "react";
import axios from "axios";
const Table = () => {
useEffect(() => {
console.log("helllllllllllllllo");
callAPI();
}, []);
const callAPI = async () => {
const url = "some URL";
const password = "Secret" ;
const username = "Consumer Key";
const data = await axios.get(
url,
{},
{
auth: {
username: username,
password: password,
},
}
);
console.log("data", data);
};
return (
<div> Hello </div>
);
};
export default Table;
On Postman, I go to the Authorization Tab and input the Username and password in their respective input fields and get the result but with axios, I getting 401 error.
Exact Error being :-
createError.js:16 Uncaught (in promise) Error: Request failed with status code 401
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:62)

You are incorrectly passing the auth headers. In axios GET, first parameter is URL and second parameter is config object. In config object, you can provide auth property for sending basic auth headers.
const data = await axios.get(url, {
auth: {
username: username,
password: password,
},
})

Related

Why does my axios create function in React does not work?

I'm working on a fullstack app with Express and React. For the calls to the backend, I use axios (version 1.1.2). Before this version, I was using a function to avoid writing the same calls to the database every time. Now, I get this error:
POST http://localhost:5005/api/auth/signup 400 (Bad Request)
Where does it come from?
This is my non working code:
const API_URL = process.env.REACT_APP_API_URL
export default axios.create({
baseURL: `${API_URL}/api`,
timeout: 1000,
headers: {
"Content-type": "application/json",
},
})
// Here, http refers to the axios.create function
class AuthService {
signup(data: any) {
return http.post("/auth/signup", data)
}
}
const handleSubmit = (e: React.ChangeEvent<HTMLFormElement>) => {
authService
.signup(inputs)
...rest
}
But this is working:
const handleSubmit = (e: React.ChangeEvent<HTMLFormElement>) => {
axios
.post(`${API_URL}/api/auth/signup`, inputs)
...rest
}
Thanks for your help!
EDIT:
When I submit the form, on the front end I get this error, which on the back end would be returned if an input is empty:
Please provide your full name.
Back end code:
if (!fullName) {
return res
.status(400)
.json({ message: "Please provide your full name." })
}
EDIT 2:
I tried to add a console.log on the back end with the req.body and this is what I get:
{}
This is the full backend code:
router.post("/signup", (req, res, next) => {
const { email, fullName, password } = req.body
console.log(req.body)
if (!fullName) {
return res
.status(400)
.json({ message: "Please provide your full name." })
}
User.findOne({ email })
.then(foundUser => {
...rest
return User.create({
email,
fullName,
password,
}).then(createdUser => {
const payload = { user: createdUser }
const authToken = jwt.sign(
payload,
process.env.TOKEN_SECRET,
jwtConfig
)
res.status(201).json({
user: createdUser,
authToken: authToken,
})
})
})
.catch(err => console.log(err))
})
And my terminal returns this:
POST /api/auth/login 401 16.919 ms - 39
EDIT 3:
This is my Express app.js:
require("dotenv/config")
require("./db")
const express = require("express")
const app = express()
require("./config")(app)
const allRoutes = require("./routes/index")
app.use("/api", allRoutes)
require("./error-handling")(app)
module.exports = app
You can find the full repo here: https://github.com/JulSeb42/tsx-express-jwt

best way to authenticate with SWR (firebase auth)

I'm doing project with React , firebase auth social signin(google, github provider) and backend(spring boot)
I'm wondering how can i use useSWR for global state for google userData
Here's my Code This is Login page simply i coded
In this page, I fetch userData(email, nickname ,, etc) with header's idToken(received from firebase auth) and backend validates idToken and send me a response about userData
This is not problem I guess.. But
// import GithubLogin from '#src/components/GithubLogin';
import GoogleLogin from '#src/components/GoogleLogin';
import { auth, signOut } from '#src/service/firebase';
import { fetcherWithToken } from '#src/utils/fetcher';
import React, { useEffect, useState } from 'react';
import useSWR from 'swr';
const Login = () => {
const [token, setToken] = useState<string | undefined>('');
const { data: userData, error } = useSWR(['/api/user/me', token], fetcherWithToken);
useEffect(() => {
auth.onAuthStateChanged(async (firebaseUser) => {
const token = await firebaseUser?.getIdToken();
sessionStorage.setItem('user', token!);
setToken(token);
});
}, []);
return (
<div>
<button onClick={signOut}>Logout</button>
<h2>Login Page</h2>
<GoogleLogin />
</div>
);
};
export default Login;
Here's Code about fetcher using in useSWR parameter
export const fetcherWithToken = async (url: string, token: string) => {
await axios
.get(url, {
headers: {
Authorization: `Bearer ${token}`,
Content-Type: 'application/json',
},
withCredentials: true,
})
.then((res) => res.data)
.catch((err) => {
if (err) {
throw new Error('There is error on your site');
}
});
};
problem
I want to use userData from useSWR("/api/user/me", fetcherWithToken) in other page! (ex : Profile Page, header's Logout button visibility)
But for doing this, I have to pass idToken (Bearer ${token}) every single time i use useSWR for userData. const { data: userData, error } = useSWR(['/api/user/me', token], fetcherWithToken);
Like this.
What is the best way to use useSWR with header's token to use data in other pages too?
seriously, I'm considering using recoil, context api too.
but I don't want to.
You can make SWR calls reusable by wrapping them with a custom hook. See the SWR docs page below.
Make It Reusable
When building a web app, you might need to reuse the data in many
places of the UI. It is incredibly easy to create reusable data hooks
on top of SWR:
function useUser (id) {
const { data, error } = useSWR(`/api/user/${id}`, fetcher)
return {
user: data,
isLoading: !error && !data,
isError: error
}
}
And use it in your components:
function Avatar ({ id }) {
const { user, isLoading, isError } = useUser(id)
if (isLoading) return <Spinner />
if (isError) return <Error />
return <img src={user.avatar} />
}

React: Unhandled error 500 when using API to get data from Prisma

I am trying to get some data from my Prisma database by using an API, but I get errors.
This is my API:
export default async function handler(req, res) {
switch (req.method) {
case 'DELETE':
const { id } = req.query
const issue2 = await db.deleteUnique(id)
res.status(204).end()
break
case 'GET':
const issue = await db.findUnique(id)
res.status(200).json({ success: true, data: issue })
break
default:
res.status(405).end()
break
}
}
And this is my index.js file that sends a call to my API:
import axios from 'axios'
import { useRouter } from 'next/router'
const Issue = () => {
const router = useRouter();
const { id } = router.query
const getIssue = async () => {
// GET-request til /api/issues/[id].js
const response = await axios.get(`/api/issues/${id}`)
}
return (
<div>
<h1>Issue {id}</h1>
<button onClick={getIssue}>Hent Id</button>
</div>
)
}
export default Issue
The error I get is "Unhandled Runtime Error" after I click the button to get the ID, I have tried everything I can think of. Can anyone help?
createError
node_modules/axios/lib/core/createError.js (16:0)
settle
node_modules/axios/lib/core/settle.js (17:0)
XMLHttpRequest.onloadend
node_modules/axios/lib/adapters/xhr.js (66:0)
there should be a try catch block of axios get request
and there is no connection between the get request and the switch block
(i meant you are not sending response.json() to the switch )

Handling API error responses with axios (multiple files)

I'm new with React and I was trying to separate my Axios http utilities in different files.
It works fine if I login with correct credentials but when I try wrong credentials and my API responses with a 401 (Bad Credentials) message Axios execute the then() method instead of the catch() method.
axios.ts
import Axios from "axios";
const JSON_CONTENT_TYPE = "application/json";
// axios configuration
const axios = Axios.create({
baseURL: process.env.REACT_APP_API_URL,
responseType: "json"
});
// ... other requests handlers
export const post = <T = any>(
url: string,
body: any,
params?: any,
contentType = JSON_CONTENT_TYPE
) => {
return axios.post<T>(url, body, {
params,
headers: { "Content-Type": contentType }
});
};
login-adapter.ts
import { ILogin } from "../../model/login.model";
import * as Http from "../axios";
import * as StorageManager from "../storage-manager";
type TokenBody = {
id_token: string;
};
export const login = (credentials: ILogin) => {
return new Promise((resolve, reject) => {
Http.post<TokenBody>("/authenticate", credentials)
.then((resp) => {
// Stores jwt in local/session storage.
// HERE IS WHEN MY APP CRASHES, The error says 'resp is undefined' and THIS ERROR (not the response from my API) is caught by the catch method below.
StorageManager.setToken(resp.data.id_token, credentials.rememberMe);
// Does another request to get user info.
Http.get("/account").then(console.log);
resolve("Success");
})
.catch((error) => reject("Error, " + error.response.data)); // THIS SHOULD SEND THE ERROR MESSAGE TO LoginPage.tsx
});
};
LoginPage.tsx
import { FormEvent, useState } from "react";
import "../../styles/LoginPage.css";
import * as LoginAdapter from "../../adapters/loginAdapters/login-adapter";
import { RouteComponentProps } from "react-router-dom";
const LoginPage = ({history}: RouteComponentProps) = {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [rememberMe, setRememberMe] = useState(false);
const submit = (e: FormEvent<HTMLFormElement>) => {
LoginAdapter.login({ email, password, rememberMe })
.then(() => {
history.push("/admin/courses");
})
.catch((error) => {
console.log(error);
});
e.preventDefault();
}
return (
<form onSubmit={submit}>
{/* <input ... email, password, and 'remember me' form fields.*/}
</form>
);
}
export default LoginPage;
When I use axios directly from the package. (import axios from "axios") it works perfectly. But I have to rewrite my api endpoint, response type, interceptors, etc. I don't know why it is not working, Am I missing something?
My interceptor was the problem, I didn't notice that the error handler should return a Promise with a reject reason.
axios.interceptors.response.use(
(resp) => resp,
(error) => {
if (
error.response.status === 401 &&
error.response.config.url !== "/account"
) {
LoginAdapter.logout();
}
// before: <nothing>
// now:
return Promise.reject(error);
}
);

Testing an HTTP post Request with mocha using nock

I'm learning how to test a frontend webapp without any connection to the API.
My problem is: I have to test an POST HTTP Request but always get an error : TypeError: loginUser(...).then is not a function.
I know my expect is not correct. I must change the data for a JWT token, and also don't know yet hot to do it.
It's a simple user authentication. Http post sending an email and password, getting back a JWT (json web token). I have to write a test to make sure I've send the correct information and get a JWT as response.
Thanks for your help
Here is my code:
//login.test.js
const expect = require('chai').expect;
const loginUser = require('../src/actions/authActions').loginUser;
const res = require('./response/loginResponse');
const nock = require('nock');
const userData = {
email: 'test#test.com',
password: '123456'
};
describe('Post loginUser', () => {
beforeEach(() => {
nock('http://localhost:3000')
.post('/api/users/login', userData )
.reply(200, res);
});
it('Post email/pwd to get a token', () => {
return loginUser(userData)
.then(res => {
//expect an object back
expect(typeof res).to.equal('object');
//Test result of name, company and location for the response
expect(res.email).to.equal('test#test.com')
expect(res.name).to.equal('Tralala!!!')
});
});
});
//authActions.js
import axios from "axios";
import setAuthToken from "../utils/setAuthToken";
import jwt_decode from "jwt-decode";
import {
GET_ERRORS,
SET_CURRENT_USER,
USER_LOADING
} from "./types";
// Login - get user token
export const loginUser = userData => dispatch => {
axios
.post("/api/users/login", userData)
.then(res => {
// Save to localStorage
// Set token to localStorage
const { token } = res.data;
localStorage.setItem("jwtToken", token);
// Set token to Auth header
setAuthToken(token);
// Decode token to get user data
const decoded = jwt_decode(token);
// Set current user
dispatch(setCurrentUser(decoded));
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
// loginResponse.js
module.exports = { email: 'test#test.com',
password: '123456',
name: "Tralala!!!"
};
Actual result:
1) Post loginUser
Post email/pwd to get a token:
TypeError: loginUser(...).then is not a function
at Context.then (test/login.test.js:37:12)
The way you called loginUser method is not correct. This method returns another function. So, instead of loginUser(userData), you must also specify the dispatch parameter e.g. loginUser(userData)(dispatch).then().
I changed the method to specify return before axios statement
export const loginUser = userData => dispatch => {
return axios // adding return
.post("/api/users/login", userData)
.then(res => {
...
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
for test, I may involve Sinon to spy the dispatch
it("Post email/pwd to get a token", () => {
const dispatchSpy = sinon.spy();
return loginUser(userData)(dispatchSpy).then(res => {
//expect an object back
expect(typeof res).to.equal("object");
//Test result of name, company and location for the response
expect(res.email).to.equal("test#test.com");
expect(res.name).to.equal("Tralala!!!");
});
});
Hope it helps

Resources