I am using yii2 for the backend and react for the frontend.
I have some login function. And a user can login. But if I look in devops -> application -> localstorage I see that there is no bearer token and user object is empty.
This is the UserController login server call:
public function actionLogin() { $username = Yii::$app->request->post('username'); $password = Yii::$app->request->post('password'); $user = User::findByUsername($username); if ($user && $user->validatePassword($password)) { return ['status' => 'success', 'data' => 'Login successful']; } else { Yii::$app->response->statusCode = 401; return ['status' => 'error', 'data' => 'Invalid username or password']; } }login form:
import * as Yup from "yup";import { ChangeEvent, MouseEvent, ReactNode, useState } from 'react'import MuiCard, { CardProps } from '@mui/material/Card'import MuiFormControlLabel, { FormControlLabelProps } from '@mui/material/FormControlLabel'import { styled, useTheme } from '@mui/material/styles'import BlankLayout from 'src/@core/layouts/BlankLayout'import Box from '@mui/material/Box'import Button from '@mui/material/Button'import CardContent from '@mui/material/CardContent'import Checkbox from '@mui/material/Checkbox'import Divider from '@mui/material/Divider'import EyeOffOutline from 'mdi-material-ui/EyeOffOutline'import EyeOutline from 'mdi-material-ui/EyeOutline'import Facebook from 'mdi-material-ui/Facebook'import FooterIllustrationsV1 from 'src/views/pages/auth/FooterIllustration'import FormControl from '@mui/material/FormControl'import Github from 'mdi-material-ui/Github'import Google from 'mdi-material-ui/Google'import IconButton from '@mui/material/IconButton'import InputAdornment from '@mui/material/InputAdornment'import InputLabel from '@mui/material/InputLabel'import Link from 'next/link'import OutlinedInput from '@mui/material/OutlinedInput'import React from "react";import TextField from '@mui/material/TextField'import Twitter from 'mdi-material-ui/Twitter'import Typography from '@mui/material/Typography'import themeConfig from 'src/configs/themeConfig'import { useAuth } from "../../../context/useAuth";import { useForm } from "react-hook-form";import { useRouter } from 'next/router'import { yupResolver } from "@hookform/resolvers/yup";interface State { password: string showPassword: boolean}// ** Styled Componentsconst Card = styled(MuiCard)<CardProps>(({ theme }) => ({ [theme.breakpoints.up('sm')]: { width: '28rem' }}))const LinkStyled = styled('a')(({ theme }) => ({ fontSize: '0.875rem', textDecoration: 'none', color: theme.palette.primary.main}))const FormControlLabel = styled(MuiFormControlLabel)<FormControlLabelProps>(({ theme }) => ({'& .MuiFormControlLabel-label': { fontSize: '0.875rem', color: theme.palette.text.secondary }}))type Props = {};type LoginFormsInputs = { username: string; password: string;};const validation = Yup.object().shape({ username: Yup.string().required("Username is required"), password: Yup.string().required("Password is required"),});const LoginPage = (props: Props) => { const [values, setValues] = useState<State>({ password: '', showPassword: false }) const { loginUser } = useAuth(); const { register, handleSubmit, formState: { errors }, } = useForm<LoginFormsInputs>({ resolver: yupResolver(validation) }); const handleLogin = (form: LoginFormsInputs) => { loginUser(form.username, form.password); console.log(form.username, form.password); }; const theme = useTheme() const router = useRouter() return (<Box className='content-center'><Card sx={{ zIndex: 1 }}><CardContent sx={{ padding: theme => `${theme.spacing(12, 9, 7)} !important` }}><Box sx={{ mb: 8, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Typography variant='h6' sx={{ ml: 3, lineHeight: 1, fontWeight: 600, textTransform: 'uppercase', fontSize: '1.5rem !important' }}> {themeConfig.templateName}</Typography></Box><Box sx={{ mb: 6 }}><Typography variant='h5' sx={{ fontWeight: 600, marginBottom: 1.5 }}> Welcome to {themeConfig.templateName}! 👋🏻</Typography><Typography variant='body2'>Please sign-in to your account and start the adventure</Typography></Box><form noValidate autoComplete='off' onSubmit={handleSubmit(handleLogin)}><TextField autoFocus fullWidth id='username' label='username' sx={{ marginBottom: 4 }} {...register("username")} /> {errors.username ? <p style={{color:'red'}}>{ errors.username.message}</p>:"" }<FormControl fullWidth> <TextField type="password" autoFocus fullWidth id='password' label='password' sx={{ marginBottom: 4 }} {...register("password")} /> {errors.password ? (<p style={{color:'red'}}>{errors.password.message}</p> ) : ("" )}</FormControl><Box sx={{ mb: 4, display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'space-between' }}><FormControlLabel control={<Checkbox />} label='Remember Me' /> </Box><Button type="submit" fullWidth size='large' variant='contained' sx={{ marginBottom: 7 }}> Login</Button><Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'center' }}><Typography variant='body2' sx={{ marginRight: 2 }}> New on our platform?</Typography><Typography variant='body2'><Link passHref href='/pages/register'><LinkStyled>Create an account</LinkStyled></Link></Typography></Box><Divider sx={{ my: 5 }}>or</Divider><Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Link href='/' passHref><IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}><Facebook sx={{ color: '#497ce2' }} /></IconButton></Link><Link href='/' passHref><IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}><Twitter sx={{ color: '#1da1f2' }} /></IconButton></Link><Link href='/' passHref><IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}><Github sx={{ color: theme => (theme.palette.mode === 'light' ? '#272727' : theme.palette.grey[300]) }} /></IconButton></Link><Link href='/' passHref><IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}><Google sx={{ color: '#db4437' }} /></IconButton></Link></Box></form></CardContent></Card><FooterIllustrationsV1 /></Box> )}LoginPage.getLayout = (page: ReactNode) => <BlankLayout>{page}</BlankLayout>export default LoginPageand client login code service:
/* eslint-disable newline-before-return */import { UserProfileToken } from "../models/User";import axios from "axios";import { handleError } from "../helpers/ErrorHandler";const api = "http://localhost:8080/v1/";export const loginAPI = async (username: string, password: string) => { try { const data = await axios.post<UserProfileToken>(api +"user/login", { method: 'post', Headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, username: username, password: password, }); return data; } catch (error) { handleError(error); }};and context:
import { createContext, useEffect, useState } from "react";import { loginAPI, registerAPI } from "../services/AuthService";import React from "react";import { UserProfile } from "../models/User";import axios from "axios";import router from 'next/router'import { toast } from "react-toastify";type UserContextType = { user: UserProfile | null; token: string | null; registerUser: (email: string, username: string, password: string) => void; loginUser: (username: string, password: string) => void; logout: () => void; isLoggedIn: () => boolean;};type Props = { children: React.ReactNode };const UserContext = createContext<UserContextType>({} as UserContextType);export const UserProvider = ({ children }: Props) => { const [token, setToken] = useState<string | null>(null); const [user, setUser] = useState<UserProfile | null>(null); const [isReady, setIsReady] = useState(false); useEffect(() => { const user = localStorage.getItem("user"); const token = localStorage.getItem("token"); if (user && token) { setUser(JSON.parse(user)); setToken(token); axios.defaults.headers.common["Authorization"] = "Bearer " + token; } setIsReady(true); }, []); const loginUser = async ( username: string, password: string ) => { await loginAPI(username, password) .then((res) => { if (res) { localStorage.setItem("token", res?.data.token); const userObj = { username: res?.data.username, email: res?.data.email, }; if (undefined === username) { //console.log(res.data.username); toast.error("Please enter valid username"); } else if (Object.keys(res).length > 0) { console.log(JSON.parse(res.config.data)); localStorage.setItem("user", JSON.stringify(userObj)); setToken(res?.data.token!); setUser(userObj!); toast.success("you are now logged in"); router.push("/"); } else { toast.error("Pleae enter valid user data"); } } }) .catch((e) => toast.warning("Server error occured")); }; const isLoggedIn = () => { return !!user; }; return (<UserContext.Provider value={{ loginUser, user, token, , isLoggedIn }}> {isReady ? children : null}</UserContext.Provider> );};export const useAuth = () => React.useContext(UserContext);and User.ts file:
export type UserProfileToken = { username: string; password: string; email: string; token: string;};export type UserProfile = { username: string; email: string;}And
console.log(JSON.parse(res.config.data));returns:
{"method": "post","Headers": {"Content-Type": "application/x-www-form-urlencoded" },"username": "margo","password": "123456789"}Question: how to retrieve the bearer token and user object?