I'm trying to implement right now in my project a real time notification ui using laravel broadcast. I already made it work by broadcasting on a public channel but once I switched on to a private channel, the error POST http://localhost:8000/broadcasting/auth 404 (Not Found) appears when loading the page.
Here's what I made sure to check so far:
I've already uncommented both the App\Providers\BroadcastServiceProvider::class and Illuminate\Broadcasting\BroadcastServiceProvider::class, in the config\app.php,
I've also included Broadcast::routes(); and tested Broadcast::routes(['middleware' => 'auth:admin']); inside the boot() method of Providers\BroadcastServiceProvider if it'll work but still no dice,
I've also tried passing the Broadcast::routes(); in routes\web.php and,
Made sure that I have included <meta name="csrf-token" content="{{ csrf_token() }}"> in the main app.
The project that I'm working on implements SPA using Vue JS which is completely separated from the backend and is only connected through api. I hope someone could give me an insight with what going wrong with my methods. Thank you!
The question was asked a long time ago, but I hope it will be useful to someone. I had the same issue using stand-alone SPA (Vue.js) and REST API (Laravel). To simplify implementation of live comments system I used laravel-echo and pusher.js. To solve the issue I specified the auth endpoint according to the "Customizing The Authorization Endpoint chapter"
https://laravel.com/docs/8.x/broadcasting#customizing-the-authorization-endpoint
I used the following approach:
authEndpoint: process.env.VUE_APP_API_ROOT + '/broadcasting/auth'
where VUE_APP_API_ROOT is "http://api.yoursite.dev
But then I got a new issue with CORS. I used JWT authentication for API endpoints and a middleware from the https://github.com/fruitcake/laravel-cors package that allows to specify 'Access-Control-Allow-Origin' headers to solve the CORS issue when SPA sends requests to the API from a different domain.
So to solve the CORS and authentication issue I added the broadcast routes to api.php and set the JWT auth middleware
Broadcast::routes(['middleware' => ['auth.jwt:api']]);
and set a custom Pusher authorizer using Laravel echo
window.Echo = new Echo({
broadcaster: "pusher",
cluster: process.env.VUE_APP_PUSHER_APP_CLUSTER,
encrypted: true,
key: process.env.VUE_APP_PUSHER_APP_KEY,
authorizer: (channel, options) => {
return {
authorize: (socketId, callback) => {
axios.post(process.env.VUE_APP_API_ROOT + '/api/broadcasting/auth', {
socket_id: socketId,
channel_name: channel.name
})
.then(response => {
callback(false, response.data);
})
.catch(error => {
callback(true, error);
});
}
};
},
})
P.S. To provide axios with JWT token I used axios interceptors that allows to get token from Vuex.
axios.interceptors.request.use(config => {
const token = store.getters['auth/accessToken'];
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
});
Related
I have a backend API in Laravel with Sanctum, and separate repository SPA in NuxtJS
I am trying to authenticate my SPA with Sanctum. I am trying to get the CSRF cookie in the browser as per Sanctum documentation.
The problem is when I call the CSRF token endpoint provided by Sanctum, I get the correct response, but no cookie is set. Just like that, no errors. It doesn't matter if I am gonna use nuxt auth or just plain old axios call.
This is what I have:
DOMAINS: API - publisher.local:8080; frontend - publisher.local:3000
NUXT AUTH CONFIG
auth: {
strategies: {
laravelSanctum: {
provider: 'laravel/sanctum',
url: 'http://publisher.local:8080',
endpoints: {
login: { url: '/api/v1/login', method: 'post' },
// logout: { url: '/auth/logout', method: 'post' },
// user: { url: '/auth/user', method: 'get' }
}
},
},
},
AXIOS CONFIG
axios: {
baseURL: 'http://publisher.local:8080/api/v1', // Used as fallback if no runtime config is provided
credentials: true,
proxy: true,
},
sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,local:3000',
Sanctum::currentApplicationUrlWithPort()
))),
session.php
'domain' => env('SESSION_DOMAIN', '.local'),
I tried different combinations and variations of these settings and none of it works. Do you guys have any idea what could be wrong?
I figured this out I think. I got it to work.
So there are.local cannot be the top-level domain and that I think was perhaps part of the problem but I am not sure.
Changing domains to just pain old localhost did the trick but this solution had one issue. It will for some unknown to me reason I would automatically get an XSRF cookie on any call to my API, regardless of which endpoint I would call. Weird.
What worked perfectly was changing the domains to api.publisher.com and publisher.com, followed by all the settings from the Sanctum docs.
Just be super careful with the domains and make sure they match and that the settings are correct. It is super easy to reconfigure that thing and very hard to diagnose it!
Hope that helps!
I want to get the currently logged in user whenever my React SPA starts, so I can show the user's information, but every time I try to get it from my Laravel back-end I get a 401.
I am using Laravel + Sanctum for my API, and using React in a different project for the front-end.
BACK-END:
I have the following in my AuthController controller:
public function user()
{
return auth()->user();
}
Inside my routes api.php I have the following route:
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::get('/user', [AuthController::class, 'user']);
Route::post('/logout', [AuthController::class, 'logout']);
});
My .env file contains the following:
SANCTUM_STATEFUL_DOMAINS=localhost:3000
SESSION_DOMAIN=localhost
FRONT-END:
I have a context that has the following:
useEffect(() => {
apiClient()
.get("/api/user")
.then((res) => {
setUser(res.data.user);
});
}, []);
and if you are wondering, my apiClient() comes from here:
import axios from "axios";
const apiClient = () => {
const api = axios.create({
baseURL: "http://localhost:8000",
withCredentials: true,
headers: {
Accept: "application/json",
},
});
return api;
};
export default apiClient;
This context is at the top level of the application.
I am not sure what's going on, my route /login is working as expected, I send the request and receive the user information as response which I set to a React state. On page refresh this state is removed because that's how Javascript works. I want to set it again using the useEffect mentioned above, so when the user loads the web app after closing the browser they can still see their information.
Thanks in advance!
To authenticate your SPA, your SPA's "login" page should first make a request to the /sanctum/csrf-cookie endpoint to initialize CSRF protection for the application:
axios.get('/sanctum/csrf-cookie').then(response => {
//Login...
});
For more information check https://laravel.com/docs/8.x/sanctum#spa-authentication
Currently I have
Route::filter('pre_api', function($route, $request)
{
}
to do the api key validation and its working fine.
Is it possible to make a plain request to route api which allow client access to api without api key?
You can write api requests in routes/api.php.
You need to install the cors package in laravel.
toutrial for install core -> https://medium.com/#KrishaWeb/cross-origin-request-blocked-error-in-laravel-5-5-a733232795e4
example :
Route::group(['middleware' => 'cors'], function() {
Route::get('/hello',function(){
return 'hello';
});
});
Building an application with Laravel, Passport and Vue. This question does not directly pertain to logging in with oAuth2, but rather consuming the api that's protected by Passport with your own javascript code, as per the docs.
When accessing the home page and using axios to get /oauth, I get a error 401, as expected.
After logging in using the default login provided by laravel (uses web auth), I can go back to the home page, and the axios request for /oauth works great; for example /oauth/clients returns the clients of the logged in user, as expected.
mounted() {
//works as expected: 401 when logged out and response when logged in via /login
axios.get('/oauth/clients')
.then(response => {
console.log(response.data)
})
//Always returns 400 error
axios.get('/api/user')
.then(response => {
console.log(response.data)
})
}
However, when I try with axios to get /api/user, I get a 400 error, with the message Unauthenticated (regardless if before or after login, same error).
//Returns a 400, always
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
If I'm correct, the fact that the /oauth routes work proves that the laravel_token, csrf, and any such things are being sent correctly. Therefore, I think that this is a server side issue, especially with the auth:api guard. In the auth config file, I've set it to use Passport, and followed all the docs.
I'm confused as to why I get a 400 error and not a 401 when calling the api, and why it's not authenticating in the first place.
Especially frustrating since according to this video (11:30 mark), it's pretty much plug 'n' play.
Same behaviour with Postman.
Q: Any solutions to this error?
Full code on GitHub.
Add this code in your app/Http/Kernel.php
'web' => [
// Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
I'm currently building a laravel 5.4 powered page to manage users. I've done all basic pages such as home, login, register, dashboard using blade templating engine. Now I'm building the User Management page. I've successfully implemented VueJS for this particular page. All components are working perfectly.
Now the problem I'm facing now is using Axios to get logged in user data from API route. At first I'm using usual api route to get auth()->user() data but it doesn't work.
I've learned that I must use Laravel Passport to do this API operation.
These are the steps I made after that:
composer require laravel/passport
php artisan migrate
php artisan passport:install
Added the Laravel\Passport\HasApiTokens trait to your App\User model
Called the Passport::routes method within the boot method of your AuthServiceProvider
Set the driver option of the api authentication guard to passport
Added the CreateFreshApiToken middleware to your web middleware group
Edited bootstrap.js file like the following :
window.axios.defaults.headers.common = {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'X-Requested-With': 'XMLHttpRequest'
};
Axios Code :
axios.post('/api/getmydata', {
params: {
type: 'raw'
}
})
.then((response) => {
console.log(response);
}).catch((error) => {
console.log(error);
});
Changed route (api.php) :
Route::group(['middleware' => 'api'], function(){
Route::post('getmydata', 'ApiController#test');
});
Added function inside ApiController :
public function test() {
$user = Auth::user();
return $user;
}
The problem here is axios somehow return error: Unauthenticated
Is there anything wrong with my code?
Or is there any other way of achieving this? Thank you
Send the access token in the header of your API request:
Application Type :application/json
Authentication : Bearer [Access-Token]