I follow tutorial authenticated Laravel app ver 9 with sanctum but i got message authenticate on method logout "AuthController"
App\Http\Controllers\Api\AuthController
<?php
namespace App\Http\Controllers\Api;
use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
//
public function login(Request $request){
$request->validate([
'email'=>['required','email'],
'password'=>['required']
]);
$user = User::where('email',$request->email)->first();
Auth::guard('web')->login($user);
if(!$user || !Hash::check($request->password, $user->password)){
return response(['message'=>'gk jelas']);
} else {
$token = $user->createToken('bisa_js-token')->plainTextToken;
$response = [
'user'=>$user,
'token'=>$token
];
return response($response);
}
}
public function logout(Request $request){
Auth::attempt([
'email'=>$request->email,
'password'=>$request->password
]);
Auth::user()->token()->delete();
return response(['message'=>'Successfully Logging out']);
}
}
Configure Sanctum
app\config\sanctum.php
<?php
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],
];
i also configured file cors.php
app\config\cors.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Cross-Origin Resource Sharing (CORS) Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your settings for cross-origin resource sharing
| or "CORS". This determines what cross-origin operations may execute
| in web browsers. You are free to adjust these settings as needed.
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
*/
'paths' => ['/api/*', 'sanctum/csrf-cookie', '/login', '/logout'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://backend.bisa_js.test','http://localhost:3000'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];
In file Kernel.php, i have uncomment first before writing file api.php
App\Http\Kernel.php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
after writing Kernel, i also write file api.php in folder routes
app\routes\api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\AuthController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::post('/login',[AuthController::class, 'login']);
Route::middleware('auth:sanctum')->post('/logout',[AuthController::class, 'logout']);
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
I built a spa application with laravel and react, after successfully logging in to the account in the cookie I can't log out in the logout controller method even though previously get /user in api was successfully sent with a bearer token
this my files are login and dropdown to authenticate login and logout.
Login.js
import React, {useState, useRef, useEffect} from "react"
import axios from "axios"
import {useCookies} from 'react-cookie'
import {useNavigate} from 'react-router-dom'
const Login = () => {
const navigate = useNavigate()
const [email, setEmail] = useState('')
const errorEmailRef = useRef(null)
const [errorEmail, setErrorEmail] = useState([])
const [password, setPassword] = useState('')
const errorPasswordRef = useRef(null)
const [errorPassword, setErrorPassword] = useState([])
const [errorMessage, setErrorMessage] = useState('')
const errorMessageRef = useRef(null)
const [cookie, setCookie, removeCookie] = useCookies(['login'])
useEffect(()=>{
if(cookie.token !== undefined && cookie.user !== undefined){
document.body.className = ''
navigate('/',{replace: true})
}
},[])
const submitForm = (e) => {
e.preventDefault()
// axios.get('http://backend.bisa_js.test/sanctum/csrf-cookie').then((response)=>{
// console.log(response)
// })
axios.post('http://backend.bisa_js.test/api/login', {email, password,
headers: {
'Accept':'application/json'
}})
.then((response)=>{
console.log(response.data)
setCookie('token',response.data.token, {path:'/'})
setCookie('user',response.data.user, {path:'/'})
navigate('/')
})
.catch((reject)=>{
if(reject.response.data.errors !== undefined){
const errors = reject.response.data.errors
errors.email !== undefined ? setErrorEmail(errors.email) : setErrorEmail([])
errors.password !== undefined ? setErrorPassword(errors.password) : setErrorPassword([])
errorEmailRef.current.className = 'block'
errorPasswordRef.current.className = 'block'
setErrorMessage(reject.response.data.message)
} else {
if(errorMessageRef.current.classList.contains('hidden')){
errorMessageRef.current.classList.toggle('hidden')
errorMessageRef.current.classList.toggle('block')
}
setErrorMessage(reject.response.data.message)
}
console.log(reject.response)
})
}
return (
<div className="w-full h-screen bg-slate-800 flex flex-col justify-center">
<div className="mb-3 p-2 w-[300px] mx-auto bg-red-800 rounded-lg shadow shadow-white text-white hidden" ref={errorMessageRef}>{errorMessage}</div>
<div className="w-[300px] mx-auto p-5 h-max rounded bg-slate-900 text-white shadow shadow-white">
<form className="bisa-js__form-login" onSubmit={submitForm}>
<div className="bisa-js__group-form mb-5">
<label className="block mb-3">Email</label>
<input type='email' value={email} onChange={(event)=>{
setEmail(event.target.value)
}} placeholder="type here your email..."
className="block p-2 text-base rounded outline-none mb-2 bg-slate-900 shadow shadow-white text-white w-full"/>
<div ref={errorEmailRef} className="hidden">
{errorEmail.map((val, ind)=>(
<p className="text-red-500 font-medium" key={ind}>{val}</p>
))}
</div>
</div>
<div className="bisa-js__group-form mb-5">
<label className="block mb-3">Password</label>
<input type='password' value={password} onChange={(event)=>{
setPassword(event.target.value)
}} placeholder="type here your password..."
className="block p-2 text-base rounded outline-none mb-2 bg-slate-900 shadow shadow-white text-white w-full"/>
<div ref={errorPasswordRef} className="hidden">
{errorPassword.map((val, ind)=>(
<p className="text-red-500 font-medium" key={ind}>{val}</p>
))}
</div>
</div>
<button type="submit" className="p-2 rounded shadow shadow-white">Login</button>
</form>
</div>
</div>
)
}
export default Login
Dropdown.js
import React, { useRef, useState } from 'react'
import { useCookies } from 'react-cookie'
import axios from 'axios'
import {useNavigate} from 'react-router-dom'
const Dropdown = () => {
const [cookie, setCookie, removeCookie] = useCookies(['login'])
const dropdownRef = useRef('')
const [toggleMenuBool, setToggleMenuBool] = useState(false)
const navigate = useNavigate()
function logout(){
axios.defaults.withCredentials = true
axios.get('http://backend.bisa_js.test/api/user', {
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${cookie.token}`
}
}).then((response)=>{
console.log(response)
})
axios.post('http://backend.bisa_js.test/api/logout', {
headers: {
'Accept':'application/json',
'Authorization':`Bearer ${cookie.token}`
}
}).then((response)=>{
console.log(response)
// removeCookie('user',{
// path: '/'
// });
// removeCookie('token',{
// path: '/'
// });
// navigate('/login')
})
}
return (
<div className='bisa-js__dropdown w-max relative'>
<button className={toggleMenuBool ? 'bisa-js__dropdown-toogle w-max py-2 px-4 border border-slate-800 text-white bg-slate-800' : 'bisa-js__dropdown-toogle w-max py-2 px-4 border border-slate-800 bg-transparent text-slate-800'} onClick={()=>{
setToggleMenuBool(!toggleMenuBool)
dropdownRef.current.classList.contains('hidden') ? dropdownRef.current.classList.remove('hidden') : dropdownRef.current.classList.add('hidden')
}} >Account</button>
<div className='bisa-js__dropdown-menu w-max absolute top-12 right-0 bg-white border border-slate-800 hidden' ref={dropdownRef}>
<div className='bisa-js__dropdown-header p-3'>
<p>{cookie.user.name}</p>
<p className='text-sm font-medium'>{cookie.user.email}</p>
</div>
<hr/>
<div className='bisa-js__logout'>
<button onClick={logout.bind(this)}>Logout</button>
</div>
</div>
</div>
)
}
export default Dropdown
Here is your logout function.
public function logout(Request $request){
Auth::attempt([
'email'=>$request->email,
'password'=>$request->password
]);
Auth::user()->token()->delete();
return response(['message'=>'Successfully Logging out']);
}
and the following piece of code expecting email and password from request.
Auth::attempt([
'email'=>$request->email,
'password'=>$request->password
]);
Make sure you are getting the email and password in the request. if not so this line will throw an error (Unauthorized) 401. As I can see your logout function is not getting email and password from the post request. See following is your logout API request.
axios.post('http://backend.bisa_js.test/api/logout', {
headers: {
'Accept':'application/json',
'Authorization':`Bearer ${cookie.token}`
}
}).then((response)=>{
console.log(response)
// removeCookie('user',{
// path: '/'
// });
// removeCookie('token',{
// path: '/'
// });
// navigate('/login')
})
I think your logout function should look like the following.
public function logout(){
Auth::user()->token()->delete();
return response(['message'=>'Successfully Logging out']);
}
OR
Here is the link to the already given answer about the logout function try this. enter link description here
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.