Laravel 8 - Setting a cookie in response not working - php

I'm using Laravel 8 for my backend and I'm trying to store my auth token in a cookie.
I want to set that cookie in my controller response, and I'm trying this way:
return response()->cookie('token', $tokenResult->accessToken, 10000);
The problem here is that Laravel can not find cookie method.
According to Laravel 8 documentation, cookie() is a method from ResponseTrait, but Laravel is trying to get it from Macroable trait:
BadMethodCallException: Method Illuminate\Routing\ResponseFactory: :cookie does not exist. in file /var/www/html/t2t-api/vendor/laravel/framework/src/Illuminate/Macroable/Traits/Macroable.php
How could I solve this issue? Thank you.
P.S.
It seems to work if I add a parameter to response() like this:
return response('Hello World')->cookie('token', $tokenResult->accessToken, 10000);
But I need a JSON response instead of this.

You should use cookie on a new \Illuminate\Http\Response
$response = new \Illuminate\Http\Response();
return $response->cookie("name","value",360);

Related

How to set a cookie on response in Laravel Lumen 8

I'm currently building a REST API with Laravel Lumen 8. I want to set a cookie if the user logged in successfully. I saw that in the Lumen 5.1 docs there was a section that showed how to send a cookie with the response (https://lumen.laravel.com/docs/5.1/responses#attaching-cookies-to-responses). But in the documentation for version 8 this section is missing. I also looked into the Laravel 8 docs (https://laravel.com/docs/8.x/responses#attaching-cookies-to-responses) and tried the following things in my routes/web.php file:
Attempt 1
$router->get('/test', function () {
return response('Hello World')->cookie(
'name', 'value', 60
);
});
But then I get the following error:
Argument 1 passed to
Symfony\Component\HttpFoundation\ResponseHeaderBag::setCookie() must
be an instance of Symfony\Component\HttpFoundation\Cookie, string
given
Attempt 2
use Illuminate\Support\Facades\Cookie;
$router->get('/test', function () {
Cookie::queue('name', 'value', 60);
return response('Hello World');
});
Error message: Target class [cookie] does not exist.
Attempt 3
$router->get('/test', function () {
$cookie = cookie('name', 'value', 60);
return response('Hello World')->cookie($cookie);
});
Error message: Call to undefined function cookie()
Attempt 4
use Symfony\Component\HttpFoundation\Cookie;
$router->get('/test', function () {
return response(null)->withCookie(new Cookie('name', 'value'));
});
This solution works, but if i set the third parameter like this new Cookie('name', 'value', 60), I don't get an error message but the cookie doesn't get set anymore.
And I'm also a bit sceptical because I never saw this in any official docs but only in this stack overflow question: Set cookie on response in lumen 5.6.
These weren't the only things I tried but nothing worked so far. Setting a cookie should be such an easy thing but I just can't achieve it. I'm pretty new to Laravel/Lumen, has it something to do with the new Version 8? Or what else am I doing wrong?
I've had the same issue, this is not pretty but it fixed it for me.
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
...
$response = new Response();
$response->headers->setCookie(Cookie::create('foo', 'bar'));
$response->send(); // <- this guy
In case you are using the jwt-auth library by Sean Tymon for JSON Web Token Authentication, this Thread may help you: https://github.com/tymondesigns/jwt-auth/issues/1594#issuecomment-395575980
Cited from the thread:
The root of the culprit I guess is that Lumen by design no longer does
cookies which I find a bit of a flaw in the light of all the blogs and
OWASP suggestions of not storing a JWT in localstorage but rather in a
httponly cookie to prevent XSS and deal with CSRF accordingly. So, the
jwt-auth doesn't include the cookie parser with the
LumenServiceProvider which is what you register in app.php as a
service provider:
$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);
So when you add
use Tymon\JWTAuth\Http\Parser\Cookies;
to the top of jwt-auth\src\Providers\LumenServiceProvider.php
and add
new Cookies($this->config('decrypt_cookies'))
into the array at the very end of the file
$this->app['tymon.jwt.parser']->setChain([<br>
new AuthHeaders,
new QueryString,
new InputSource,
new LumenRouteParams,
new Cookies($this->config('decrypt_cookies')),
]);
then you should be able use the cookie authentication in Lumen as
well.

Laravel Socialite Implement stateless for Twitter

I would like to implement stateless method to Twitter but it seems that it is not available for TwitterProvider class as it returns
Call to undefined method Laravel\Socialite\One\TwitterProvider::stateless()
Here is my redirectToProvider method currently.
public function redirectToProvider($socialMedia)
{
$provider = strtolower($socialMedia);
return Socialite::driver($provider)->stateless()->redirect();
throw new NotFoundHttpException;
}
What is the correct implementation or what do I miss?
As mentioned by #driesvints from this question #415 I've opened at the Laravel Socialite repository, stateless is unavailable for Twitter since it uses OAuth 1.0.
They already pushed a PR #5661 to update also the Laravel Docs mentioning this specification. Click the link to see the update. Staless Authentication
I would update this answer if whatever my solution would be.

How to queue cookies in lumen?

I am trying to queue various cookies in response in Lumen.
I've added \Illuminate\Cookie\ into my Composer.
I added Following code in app.php
$app->singleton('cookie', function () use ($app) {
return $app->loadComponent('session', 'Illuminate\Cookie\CookieServiceProvider', 'cookie');
});
$app->bind('Illuminate\Contracts\Cookie\QueueingFactory', 'cookie');
In My Controller, I am trying the following code
Cookie::queue(Cookie::make('test', 'tada', 10, '/'));
//Few more business logic here: before returning the response
$response = new \Illuminate\Http\Response('exit');
return $response->withHeaders($headers);
I can see my queued cookies using Cookie::getQueuedCookies()
but still, after a response, my cookie is nowhere to be found.
I tried various answers from StackOverflow questions but still couldn't resolve it
I can't use response()->withCookie() solution because I am creating cookies at various points of my code, and can't pull them together at the time of response
Queued cookies in Laravel are handled by the \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse class.
It begs the question why you'd use Lumen if you wanted cookies support but you should be able to add this middleware to your HTTP stack in Lumen.

Laravel cookie unexpected output i.e. encrypted result on service provider

I am developing a package where I am registering ServiceProvider and inside my class methods I am saving cookie data as this
Cookie::queue(Cookie::make('my_name', 'manash', 120));
and I am retrieving like this
Cookie::get('my_name')
but I am not getting the value as I have stored, instead it is outputting me this value
eyJpdiI6InlcL3VxNklrejlKemxLQ012T0pcL3U1QT09IiwidmFsdWUiOiJpbzRmajVEUU90YkhhdTdpeFNlcURBPT0iLCJtYWMiOiI1MTFiMTk5YjY3ZTczMzI2Nzc1MGI1Mzk3NmU1MjJhYjE3MWRhYWE2OGQ4NWE1Y2Y2NDgyZWQ1YmYxOGQ4OWU1In0=
I think it encrypted, but as per my knowledge it should be automatically decrypted when we use get method.
I am using laravel 5.3.28
What happens is that all cookies created by laravel are encrypted and signed with an authentication code.
Have you tried with the request?
Like this:
Illuminate\Http\Request
Request $request;
$request->cookie('my_name');
Check if your middleware is not triggering before Encrypt Cookie middleware
Try https://laravel.com/docs/master/encryption see if it works

Laravel 5.3 Passport API unauthenticated in Postman using personal access tokens

I have set-up Laravel using passport as per the documentation here: https://laravel.com/docs/5.3/passport
A few people have asked about this using the oAuth implementation but I'm trying to use the personal access tokens not oAuth. One suggestion was to remove the auth middleware but obviously this leaves the application wide open so anyone can make requests.
I have the following route (in routes/api.php):
Route::get('/test', function(){
return 'returned string from test route';
})->middleware('auth:api');
This works if I remove the auth middleware so the route is working correctly but when enabling the auth middleware again I get the following error in postman:
{"error":"Unauthenticated."}
These are the headers being sent via postman:
GET /api/test HTTP/1.1
Host: localhost:8000
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImU4ZmY5MDMwY2EyM2E2MDYwODViN2Y3ZWNiMzcxNDY1MzQxNDViNTk4ODU4NmZhNDljYzU2YjMzYWZiNzhkYTk5OTIwZWMzYzEwNTBkNjZjIn0.eyJhdWQiOiIyIiwianRpIjoiZThmZjkwMzBjYTIzYTYwNjA4NWI3ZjdlY2IzNzE0NjUzNDE0NWI1OTg4NTg2ZmE0OWNjNTZiMzNhZmI3OGRhOTk5MjBlYzNjMTA1MGQ2NmMiLCJpYXQiOjE0NzU1MDMxNjUsIm5iZiI6MTQ3NTUwMzE2NSwiZXhwIjowLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.IpzKK29dJCpliUXQvPRss87kGFngFcXXwV3jRwhbZOZLxl-4UV70cBsSigmqUuBsHQ4onVl_Cjcq6cEmMFvTZZr7D9AtY3EmScvMPjoFh4KQ3wgd5CoyWfcLQgoBxbElNxL0xW2fIQhpeQd_8Yz_Pr5BByGVTpxfg4JJZ4PzovvZsa2R3izYtqw6-qeurQOtsfOnot5uoLDeDDc76klifnfHfOcNZSoIFGNP3gIGKYBe6lfFuDViR_mQkwQS5_UmERt3GSkEvJjGMtwcRjWY7VPAJ4tvWLnyLw0roGU2e37L0wsqfJ8OrG0Cipv-anXAW_utSo-fiVMr8ZeAWIPguq73Zd44x95YY3nNPOKD5dVIRZM7rQgdhjIwTEz1ggtSXLp-Fu3QOtXaHUahCHvjOTdiTYEa-GR4TZ5wGzt-aRhjdBB7WTe0C6T9ZWVwQr0kJk8AxW6ne87wwJYp_shGunTclZ3SCq5VYg2K_MclbJl65-dT8x-nwqg0lqfNx9s1wmtryrMFIPoBEyaGNEK1aWGHKq418-BIQ1_UAhcHHtEXclWvsGWwhyo3aso-E-sCN2o_IkYvSboIsdFAIXvDvQmoAwis6f1J57zWH8AW1ynCFcBgzBDjIyiaCE5nqtb_4zbEXr8L1EbcllbtZkq3vd9w996kO7xlpBEWwPY8IWg
Accept: application/json
Cache-Control: no-cache
Postman-Token: 6bc483b2-23df-acce-7eef-5a443f8f5d45
Firstly, NEVER modify the vendor files unless you have a fully legitimate reason for doing so and there's a feature you wish to see implemented or a bug you've discovered and fixed in the package you're using.
Expiration time on the JWT might be already set to expire as soon as it's made. Here's a link you can use to check the "ttl" (Time To Live) field of your access tokens:
https://jwt.io/
If you find that your tokens are expiring on creation, you can go to your app\providers\AuthServiceProvider.php class and add in these methods on use of Passport Class:
use Carbon\Carbon;
use Laravel\Passport\Passport;
...
Class AuthServiceProvider extends ServiceProvider {
...
...
public function boot() {
$this->registerPolicies();
Passport::routes();
Passport::tokensExpireIn(Carbon::now()->addYears(20));//You can also use addDays(10)
Passport::refreshTokensExpireIn(Carbon::now()->addYears(20));//You can also use addDays(10)
Passport::pruneRevokedTokens(); //basic garbage collector
}
}
Make sure you're using the most recent version of Passport
Currently I'm on version 1.0.8 but I might already be out of date as they and the community are constantly pushing new revisions every few weeks.
Here are links to some related issues regarding this problem. You might be able to locate your answer within one of the below links. If what's mentioned above isn't what you're looking for.
Passport - "Unauthenticated." - Laravel 5.3
Very Detailed
https://github.com/laravel/passport/issues/151
in passport.php there are two functions
public static function tokensExpireIn(DateTimeInterface $date = null)
{
if (is_null($date)) {
return static::$tokensExpireAt
? Carbon::now()->diff(static::$tokensExpireAt)
: new DateInterval('P100Y');
} else {
static::$tokensExpireAt = $date;
}
return new static;
}
/**
* Get or set when refresh tokens expire.
*
* #param \DateTimeInterface|null $date
* #return \DateInterval|static
*/
public static function refreshTokensExpireIn(DateTimeInterface $date = null)
{
if (is_null($date)) {
return static::$refreshTokensExpireAt
? Carbon::now()->diff(static::$refreshTokensExpireAt)
: new DateInterval('P100Y');
} else {
static::$refreshTokensExpireAt = $date;
}
return new static;
}
you must change P100Y to P1Y. and also in PassportserviceProvider.php at line 101 there is code
$server->enableGrantType(
new PersonalAccessGrant, new DateInterval('P100Y')
);
change P100Y to P1Y. hope it helps you :)
Please check if the token was copied properly, i always observed when i copy the personal tokens, in the last there is a word 'Close' copied also.
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImU4ZmY5MDMwY2EyM2E2MDYwODViN2Y3ZWNiMzcxNDY1MzQxNDViNTk4ODU4NmZhNDljYzU2YjMzYWZiNzhkYTk5OTIwZWMzYzEwNTBkNjZjIn0.eyJhdWQiOiIyIiwianRpIjoiZThmZjkwMzBjYTIzYTYwNjA4NWI3ZjdlY2IzNzE0NjUzNDE0NWI1OTg4NTg2ZmE0OWNjNTZiMzNhZmI3OGRhOTk5MjBlYzNjMTA1MGQ2NmMiLCJpYXQiOjE0NzU1MDMxNjUsIm5iZiI6MTQ3NTUwMzE2NSwiZXhwIjowLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.IpzKK29dJCpliUXQvPRss87kGFngFcXXwV3jRwhbZOZLxl-4UV70cBsSigmqUuBsHQ4onVl_Cjcq6cEmMFvTZZr7D9AtY3EmScvMPjoFh4KQ3wgd5CoyWfcLQgoBxbElNxL0xW2fIQhpeQd_8Yz_Pr5BByGVTpxfg4JJZ4PzovvZsa2R3izYtqw6-qeurQOtsfOnot5uoLDeDDc76klifnfHfOcNZSoIFGNP3gIGKYBe6lfFuDViR_mQkwQS5_UmERt3GSkEvJjGMtwcRjWY7VPAJ4tvWLnyLw0roGU2e37L0wsqfJ8OrG0Cipv-anXAW_utSo-fiVMr8ZeAWIPguq73Zd44x95YY3nNPOKD5dVIRZM7rQgdhjIwTEz1ggtSXLp-Fu3QOtXaHUahCHvjOTdiTYEa-GR4TZ5wGzt-aRhjdBB7WTe0C6T9ZWVwQr0kJk8AxW6ne87wwJYp_shGunTclZ3SCq5VYg2K_MclbJl65-dT8x-nwqg0lqfNx9s1wmtryrMFIPoBEyaGNEK1aWGHKq418-BIQ1_UAhcHHtEXclWvsGWwhyo3aso-E-sCN2o_IkYvSboIsdFAIXvDvQmoAwis6f1J57zWH8AW1ynCFcBgzBDjIyiaCE5nqtb_4zbEXr8L1EbcllbtZkq3vd9w996kO7xlpBEWwPY8IWg Copy
If this is not your case check if that token exist, or generate a new one. you can use this format to protect route like this
Route::middleware('auth:api')->get('/home', function(){
return 'test';
});
I Had this problem ... two hours down the pan. Something very strange was happening and in my case I think Postman was the culprit.
Inspect the received header to rule it out:
Route::get('/test', function(){
dd( Request::header());
})/*->middleware('auth:api')*/; //disable auth middleware to inspect header
this is the strange thing I found:
.........
"authorization" => array:1 [
0 => b"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ ................
what the hell was the 'b' before Bearer ACCESS_TOKEN ???
I typed it out again and it dissapeared and auth middleware started working.
Inspect the header exactly and then add the middleware back. This might just be the cause!

Categories