Private Channel not working in Laravel - laravel

In my ChatEvent i called function
public function broadcastOn()
{
return new Channel('chat');
}
And in app.js i have Echo.
Echo.channel('chat')
.listen('ChatEvent', (e) => {
this.chat.message.push(e.message);
console.log(e);
})
It works pretty well. But, when i change Channel to PrivateChannel in function broadcastOn() and in app.js I change
Echo.private('chat')
.listen('ChatEvent', (e) => {
this.chat.message.push(e.message);
console.log(e);
})
I have error POST broadcasting/auth 403 (Forbidden) ## And
Can I use Channel instead of PrivateChannel?

Like mentioned in document you have to define the authorization rule for this private channel
https://laravel.com/docs/5.5/broadcasting#authorizing-channels
edit your routes/channels.php file
Broadcast::channel('chat', function ($user) {
return true; //for public access
// or
return $user->can('chat'); //using gate
});
else use the channel for public access

When you use Private or PresenceChannel, Fix Error 403 /broadcasting/auth with Laravel version > 5.3 & Pusher, you need change your code in resources/assets/js/bootstrap.js with
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your key',
cluster: 'your cluster',
encrypted: true,
auth: {
headers: {
Authorization: 'Bearer ' + YourTokenLogin
},
},
});
And in app/Providers/BroadcastServiceProvider.php change by
Broadcast::routes()
with
Broadcast::routes(['middleware' => ['auth:api']]);
or
Broadcast::routes(['middleware' => ['jwt.auth']]); //if you use JWT
it worked for me, and hope it help you.

Try this
in Chat event add
public function broadcastAs()
{
return 'new.chat';
}
in your javascript file
Echo.channel('chat')
.listen('.new.chat', (e) => {
console.log(e);
})

if use api
window.Echo.connector.options.auth.headers['Authorization'] = `Bearer ${user.api_token}`;
if use session auth without top code

Related

Axios gives undefined while accessing data at Vue's componenet in Laravel

I'm using Laravel and Vue's component, and when i try to access the banners property from response returned by axios in vue component it gives me undefined.
I am accessing the perperty like response.data.banners
I'm returning data from controller in following way:
public function getBanners(Request $request){
return response()->json(['
banners'=> BannerImage::active()->get()
]);
}
Here is how i am accessing axios response
<script>
export default {
data: function() {
return {
banners: []
}
},
mounted() {
axios.get("getBanners").then((res)=> {
console.log(res);
console.log(res.data);
console.log(res.data.banners);
this.banners = res.data.banners;
});
console.log('Component mounted.')
}
}
</script>
Response by axios
All is working before accessing the banners property. Is there anything i am not doing correct ?
You have an linebreak ↩ between ' and banners, which is shown in the console line 2 "↩ banners":
Problem
public function getBanners(Request $request){
return response()->json([' // <-- ↩ line break
banners'=> BannerImage::active()->get()
]);
}
Correct
public function getBanners(Request $request) {
return response()->json([
'banners' => BannerImage::active()->get()
]);
}

React-Native fetch post to lumen/laravel returns MethodNotAllowed(405) but postman works

I know this questions have been asked before but non of the answers worked for me.
I am working with React Native and sending API's to Lumen-Backend and i realised that all POST request to LUMEN returns 405 error. Tested it with Postman and it works very fine.
Tried using fetch and axios but they all return 405 errors. Find codes Bellow
Postman request working image
FETCH CALL
const BASE_URL = 'http://192.168.43.232/2019/betbank_api/public/api/';
const url = '/app/auth/login/'
const endPoint = BASE_URL.concat(url);
const data ={ email: 'okeke', password:'passs' }
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
headers: {
'Content-Type': 'application/text'
},
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
return await response.text(); // parses JSON response into native JavaScript objects
}
postData(endPoint, { email: 'okeke', password:'passs' })
.then((data) => {
console.log(data); // JSON data parsed by `response.json()` call
alert(data)
});
Also tried implementing the same thing using AXIOS
but ir returns same 405 error. Find Axios code bellow
axios.post(endPoint, data, {
headers: {
'Accept': 'application/json;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8',
}
}).then( (response)=>{
console.log(JSON.stringify(response.data))
alert(JSON.stringify(response.data))
}
).catch( (error)=>{
console.log(error)
alert(error)
})
Find the Lumen Route - API bellow
$router->group(['prefix' => 'api'], function () use ($router) {
$router->post('/app/auth/login', 'AppUserController#postLogin');
});
FInd the method postLogin Bellow
class AppUserController extends Controller
{
protected $jwt;
public function __construct(JWTAuth $jwt)
{
$this->jwt = $jwt;
}
public function postLogin(Request $request)
{
$email = $request->input('email');
$this->validate($request, [
'email' => 'required|email|max:255',
'password' => 'required',
]);
try {
if (! $token = $this->jwt->attempt($request->only('email', 'password'))) {
return response()->json(['status'=>'error','data'=> 'Invalid username and passowrd'], 401);
}
} catch (\Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
return response()->json(['token_expired'], 500);
} catch (\Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {
return response()->json(['token_invalid'], 500);
} catch (\Tymon\JWTAuth\Exceptions\JWTException $e) {
return response()->json(['token_absent' => $e->getMessage()], 500);
}
return response()->json(compact('token'));
}
}
Everythings seems in order but somehow, neither fetch or axios would work when i use the POST method.
But if i change it to GET method, the error stops but the issue would now be how to get the data's been posted from the APP.
QUESTION
Why would all Post request from my App (React Native) be returning 405 from Lumen/Laravel

On get request why do I get back the blade view, when I should get data from the database instead?

I a have the following get request, which is executed on mounted().
In some weird mysterious ways, I get back my main view app.blade as a response when I am clearly requesting some data from the database.
Can someone spot what I messed up?
My get request on the front-end:
mounted() {
this.getProjectRequests();
},
methods: {
getProjectRequests: function() {
var self = this;
let clientId = this.$route.path.substring(
this.$route.path.lastIndexOf("/") + 1
);
axios({
method: "get",
url: "/get-project-requests/" + clientId
})
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
// TODO error handling
});
}
}
My route:
Route::get('/get-project-requests/{client_id}',
'SinglePageController#getProjectRequests');
And my controller method:
public function getProjectRequests($clientId) {
try {
$projectRequests = ProjectRequest::where('client_id',
$clientId)->value('name');
return response()->json( [
'success'=> true,
'projectRequests' => $projectRequests
]);
} catch(\Exception $e){
return ['success' => false, 'message' => 'getting
project requests failed'];
}
}
I think this ProjectRequest::where('client_id', $clientId)->value('name'); giving exception.
Either you check your laravel.log inside storage/logs folder or change that method into
// Not working on eloquent model
$valueOject = ProjectRequest::where('client_id',$clientId)->value('name');
// DB facade its working. Change to this method
$valueOject = DB::table('{your_table}')->where('client_id', $clientId)->value('name');
dd($valueOject);

Protect laravel api service with Okta and JWT

Trying to put together a solution to protecting a Laravel 5.4 api using OKTA and JWT. I have an SPA that logs into my application via OKTA and retrieves an access_token and id_token. It also passes this to API calls in the header using 'Authorization': Bearer ${accessToken} but now i am struggling to find a solution to verify this access token with OKTA within the Laravel backend. been looking at tymon/jwt-auth but cant workout how to add a custom solution to verifiy the token but i would assume it can be done using okta/jwt-verifier does anyone have any samples/guide? also looked at laravel/socialite and socialiteproviders/okta but that seems more about a traditional backend login rather than an SPA
Our okta/jwt-verifier library should be able to help you out here. You will have to create a custom middleware solution to capture and authorize the request based on the bearer token. Once you have that middleware set up, inside of the verifier library, you can run the following to verify the accessToken.
$jwtVerifier = (new \Okta\JwtVerifier\JwtVerifierBuilder())
->setAudience('api://default')
->setClientId('{clientId}')
->setIssuer('https://{yourOktaDomain}.com/oauth2/default')
->build();
$jwt = $jwtVerifier->verify($jwt);
By changing the client id and your okta domain above, you should be able to pass in the accessToken to the verify method. If you do not get any exceptions, you can assume that the jwt is valid and approve the request.
See the github repo readme for information about what you have access to once you verify the validity of the JWT
For those finding this post. In the SPA make sure you also define the issuer, this should be a useful start...
//react login
this.oktaAuth = new OktaAuth({
url: props.config.oktaUrl
,clientId:props.config.clientId
,redirectUri:props.config.redirectUri
,issuer: props.config.issuer
});
this.oktaAuth.signIn({
username: this.state.username,
password: this.state.password
})
.then((response) => {
if (response.status === 'SUCCESS') {
this.setState({
sessionToken: response.sessionToken
});
this.oktaAuth.token.getWithoutPrompt({
responseType: ['id_token', 'token']
,scopes: ['openid', 'email', 'profile']
,sessionToken: response.sessionToken
})
.then((tokenOrTokens) => {
this.setState({
tokenOrTokens: tokenOrTokens
});
window.localStorage.setItem('access_token', tokenOrTokens[1].accessToken);
})
.catch(function(err) {
console.log('err', err);
});
}
})
//api call
const accessToken = window.localStorage.getItem('access_token') || null;
const config = {
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Bearer ${accessToken}`
},
};
fetch(url, config)
.then((response) => {
...
//laravel api route
Route::group(['prefix' => 'restricted', 'middleware' => ['okta.validate']], function() {
Route::get('/getprotecteddata', 'MyController#getProtectedData');
});
//laravel kernel.php
protected $routeMiddleware = [
...
'okta.validate' => \App\Http\Middleware\ValidateOKTAToken::class,
];
//laravel middleware
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class ValidateOKTAToken
{
public function handle($request, Closure $next)
{
$token = $this->parseAuthHeader($request);
$jwt = $this->validate($token);
\Log::info("ValidateOKTAToken jwt=" . json_encode($jwt->toJson()));
return $next($request);
}
protected function validate($token) {
$oktaClientId = env('OKTA_CLIENTID');
$oktaIssuer = env('OKTA_ISSUER');
$oktaAudience = env('OKTA_AUDIENCE');
$jwtVerifier = (new \Okta\JwtVerifier\JwtVerifierBuilder())
->setAudience($oktaAudience)
->setClientId($oktaClientId)
->setIssuer($oktaIssuer)
->build();
$jwt = $jwtVerifier->verify($token);
return $jwt;
}
protected function parseAuthHeader(Request $request, $header = 'authorization', $method = 'bearer')
{
$header = $request->headers->get($header);
if (! starts_with(strtolower($header), $method)) {
return false;
}
return trim(str_ireplace($method, '', $header));
}
}

Laravel Passport consuming own API fail

I'm building a SPA with Vue. My front-end and my back-end (Laravel) are in the same codebase. I want to approach my API (that is in my back-end) via the Laravel Passport Middleware CreateFreshApiToken. I'm approaching my sign in method in my AuthController via web.php.
My problem:
As soon as I'm successfully signed in via my sign in method I would expect that at this time Passport created the laravel_token cookie. This is not the case. The cookie is created after a page refresh. But as I said I'm building a SPA and that's why I don't want to have page refreshes.
What I want:
I want to sign in via my sign in method then use the Passport CreateFreshApiToken middleware. After that I want to use the (just created in the middleware) laravel_token cookie so that I can correctly and safely speak to my own API in my signed-in section of the SPA.
More information:
Kernel.php
// Code...
protected $middlewareGroups = [
'web' => [
// other middlewares...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
];
// Code...
AuthController.php
// Code...
public function login()
{
if (Auth::attempt(['email' => Input::get('email'), 'password' => Input::get('password')], true)) {
return response()->json([
'user' => Auth::user(),
'authenticated' => auth()->check(),
]);
}
return response()->json(['authenticated' => false], 401);
}
// Code...
Login.vue
// Code...
methods: {
login: function (event) {
event.preventDefault();
this.$http.post(BASE_URL + '/login', {
email: this.email,
password: this.password,
})
.then(function (response) {
localStorage.user_id = response.body.user.id;
router.push({
name: 'home'
});
});
},
},
// Code...
What goes wrong? This:
CreateFreshApiToken.php
// Code...
public function handle($request, Closure $next, $guard = null)
{
$this->guard = $guard;
$response = $next($request);
// I'm signed in at this point
if ($this->shouldReceiveFreshToken($request, $response)) { // returns false unless you refresh the page. That's why it won't create the laravel_token cookie
$response->withCookie($this->cookieFactory->make(
$request->user($this->guard)->getKey(), $request->session()->token()
));
}
return $response;
}
protected function shouldReceiveFreshToken($request, $response)
{
// both methods below return false
return $this->requestShouldReceiveFreshToken($request) &&
$this->responseShouldReceiveFreshToken($response);
}
protected function requestShouldReceiveFreshToken($request)
{
// $request->isMethod('GET') - returns false because it's a POST request
// $request->user($this->guard) - returns true as expected
return $request->isMethod('GET') && $request->user($this->guard);
}
protected function responseShouldReceiveFreshToken($response)
{
// $response instanceof Response - returns false
// ! $this->alreadyContainsToken($response) - returns false as expected
return $response instanceof Response &&
! $this->alreadyContainsToken($response);
}
// Code...
I assume it is possible what I want to achieve right? If yes, how?
I had the same issue, decided to stick to client_secret way. I guess it's not relevant for you now, but I've found 2 ways of receiving the laravel token without refresh:
1) sending dummy get request with axios or $http, whatever you use - token will get attached to response;
2) changing requestShouldReceiveFreshToken method in CreateFreshApiToken.php - replace return $request->isMethod('GET') && $request->user($this->guard); with return ($request->isMethod('GET') || $request->isMethod('POST')) && $request->user($this->guard);
function consumeOwnApi($uri, $method = 'GET', $parameters = array())
{
$req = \Illuminate\Http\Request::create($uri, $method, $parameters, $_COOKIE);
$req->headers->set('X-CSRF-TOKEN', app('request')->session()->token());
return app()->handle($req)->getData();
}

Resources