Laravel cookie session lifetime - session

I used my Laravel as a OAuth2 client, and I need to keep token i cookies. So, I set driver to cookie and keep default value for lifetime 120
When any user check remember me on login, I tried to change lifetime with code:
$lifetime = time() + 60 * 60 * 24 * 365;// one year
Config::set('session.lifetime', $lifetime);
But without success. In any another controller I checked value of lifetime and every time I get default value.
\Log::info(\Config::get('session.lifetime'));
Edit #1:
It is enough?
if(Input::has('rememberMe')) {
$lifetime = time() + 60 * 60 * 24 * 365; // one year
Session::put('Expires', $lifetime);
}
Edit #2:
I put acess_token key on the same way as Expires in example above, like:
public function signin() {
/**
* Code for getting *client_code* and *client_state* from API server
*/
$access_token = $this->provider->getAccessToken('authorization_code', $form_data);
// $access_token is object and contain all data (access_token, refresh_token, expires)
Session::put('access_token', $access_token);
Session::put('refresh_token', $access_token->refreshToken);
Session::put('token_expires', $access_token->expires);
if(Input::has('rememberMe')) {
$lifetime = time() + 60 * 60 * 24 * 365; // one year
Session::put('expires', $lifetime);
}
return Response....
}
This is the 'default' Laravel session (I changed driver from file to cookie in /app/config/session.php). I know life time should be set in /app/config/session.php file, but as you can see I need longer life time for Remember me option

Actually when you are setting the value like this in a Controller:
$lifetime = time() + 60 * 60 * 24 * 365;// one year
Config::set('session.lifetime', $lifetime);
It's not updating the value in the file, instead it sets it for the current request only (in memory) and when you check the value using this from another Controller/Request like this:
Config::get('session.lifetime');
You are getting the value from the original value from file system. It's mentioned in the documentation as given below:
Configuration values that are set at run-time are only set for the
current request, and will not be carried over to subsequent requests.

Since it seems to be OK to use cookies as the session driver in your case, you could set the session lifetime to one year in /app/config/session.php by default and store the expiration date of the cookie along with the token in the session. That would allow you to control artificially the validity of the cookie.
Basically, your signin method could look like this:
public function signin() {
/**
* Code for getting *client_code* and *client_state* from API server
*/
$access_token = $this->provider->getAccessToken('authorization_code', $form_data);
// $access_token is object and contain all data (access_token, refresh_token, expires)
Session::put('access_token', $access_token);
Session::put('refresh_token', $access_token->refreshToken);
Session::put('token_expires', $access_token->expires);
if (Input::has('rememberMe')) {
$expires = time() + 60 * 60 * 24 * 365; // one year
} else {
$expires = time() + 60 * 60 * 2; // two hours
}
Session::put('cookie_expires', $expires);
return Response....
}
Then, any time you want to use the access_token, you would check that cookie_expires isn't past first (and if it is, redirect the user to the login page after clearing the session, for example).

I have no idea where the Session::put('expires', $lifetime); will be used. To me, it seems like a normal cookie variable, not actual lifetime associated with any cookie.
You will need to set the cookie lifetime before your cookies are set, and do it the way that Laravel knows you're setting a new cookie lifetime value.
public function signin() {
$access_token = $this->provider->getAccessToken('authorization_code', $form_data);
if (!$access_token) {
return Response... // Respond some other way if authentication failed.
}
// Check rememberMe first so you can set the right session.lifetime before setting any cookies.
if(Input::has('rememberMe')) {
$lifetime = time() + 60 * 60 * 24 * 365; // one year
Config::set('session.lifetime', $lifetime);
}
Session::put('access_token', $access_token);
Session::put('refresh_token', $access_token->refreshToken);
Session::put('token_expires', $access_token->expires);
return Response....
}
I also took the chance to add if (!$access_token) { before setting the cookie since you won't always be authenticating successfully.

Friends Please use the following function instead of numbers
strtotime("+1 year")
It makes more sense for humans

Related

Laravel 7 force user to enter password

I want to know how can I force user to re-enter his password on certain route action?
Let say if user wants to edit product before save process happens he has to input his password and if it was correct then saving is allowed.
Is there any default middleware for password in laravel 7? or should i make myself?
What do you suggest?
Update
I've found this but it's only work on web routes, i need same thing to work on API routes.
Problem with this middleware is that it except sessions which is only available on web middlewares. I tried to add \Illuminate\Session\Middleware\StartSession::class, into api middleware but still getting this error
RuntimeException: Session store not set on request.
Why not just rewrite shouldConfirmPassword() method?
Session is only used to check when was the password confirmed at. If you are requiring password confirmation every time, just rewrite the method to return true:
/**
* Determine if the confirmation timeout has expired.
*
* #param \Illuminate\Http\Request $request
* #return bool
*/
protected function shouldConfirmPassword($request)
{
return true;
//$confirmedAt = time() - $request->session()->get('auth.password_confirmed_at', 0);
//return $confirmedAt > config('auth.password_timeout', 10800);
}
For those who stumble on this, the solution is setting config('password_timeout') to 1 i.e 1 second.
'password_timeout' => 1,
You might think that setting it to 0 should work but it doesn't and that's because of this line in the constructor of the Illuminate\Auth\Middleware\RequirePassword class
$this->passwordTimeout = $passwordTimeout ?: 10800;
which defaults $this->passwordTimeout to 3 hours when config('password_timeout') is not set (null) or 0.
The RequirePassword middleware is being bound to the application container in the registerRequirePassword method of the Illuminate\Auth\AuthServiceProvider class

Reset Cache TTL in each Access

I was wondering if there is any way to update cache TTL from the last time it has accessed?
currently, I have a method to login to adobe connect with API call and API session is valid for 4 days from the last call.
but my cache driver only keeps session in the cache for 4 days from the moment that is added. but I want to keep it for 4 days since the last time it has accessed!
is there any way to update Cache TTL?
I'm sure forgetting and reinserting key is not best practice.
/**
* Login Client Based on information that introduced in environment/config file
*
* #param Client $client
*
* #return void
*/
private function loginClient(Client $client)
{
$config = $this->app["config"]->get("adobeConnect");
$session = Cache::store($config["session-cache"]["driver"])->remember(
$config['session-cache']['key'],
$config['session-cache']['expire'],
function () use ($config, $client) {
$client->login($config["user-name"], $config["password"]);
return $client->getSession();
});
$client->setSession($session);
}
You could listen for the event CacheHit, test for the key pattern, and reset the cache for that key with a new TTL.
To do that, you should create a new listener and add it to the EventServiceProvider:
protected $listen = [
'Illuminate\Cache\Events\CacheHit' => [
'App\Listeners\UpdateAdobeCache',
]
];
And the listener:
class UpdateAdobeCache {
public function handle(CacheHit $event)
{
if ($event->key === 'the_cache_key') { // you could also test for a match with regexp
Cache::store($config["session-cache"]["driver"])->put($event->key, $event->value, $newTTL);
}
}
}

Can't take Laravel cookie that's been set

I have a checkbox in my login form and if it is checked I want to save user's email and password in a cookie so then he'll be automatically logged in. This is the part of my code that checks if the checkbox is checked and sets the cookie.
if ($remember == 'on') {
$array = array(
"email" => $email,
"password" => $password
);
$time = time() + (10 * 365 * 24 * 60 * 60);
Cookie::queue('user', serialize($array), $time);
}
But when I try to get the cookie and print it out it prints "false".
$cookie = Cookie::get('user');
dd(unserialize($cookie));
How can I get the cookie? It shows the cookie that's been set in inspect.
What's the best way to check if the cookie is set so i'll redirect the user to profile view straight away? Do I have to write a middleware for it?
The problem is your dd function call.
Cookies will store in user's browser when he retrieve the response with your Cookies attached (set-cookie headers), and you can read them in the next request that he will send to you.
when you call dd, it breaks the response chain and removes the set-cookie headers.
just remove the dd and in another route write:
dd(unserialize(\Request::cookie('user')));

sails.js Sessions - rememberme functionality

I have been trying to implement rememberme functionality using sails. I want a session to persist until the browser is closed. However, if a rememberme checkbox is ticked when the user logins in I want the session to persist for 30 days. I used the remember me passport strategy from here:
https://github.com/jaredhanson/passport-remember-me
but it ends up sitting on top of the sails session and the one called first ends up superseding the other.
You can set the cookie age just before calling the login function.
I did it in my login controller -> passport.callback.
passport.callback(req, res, function (err, user, challenges, statuses) {
...
if (req.param('remember', false) == true) {
req.session.cookie.maxAge = 1000 * 60 * 60 * 24 * 30;
}
req.login(user, function (err) {
...
}
}
This doesn't really feel right and, if you are sending some other cookies when logging in, it will affect their lifetime as well.
But it works and I went with it since finding documentation for sails-related stuff is like digging oil.
Also, I noticed that Passport was not destroying sessions properly upon and had to do it manually by calling req.session.destroy(); in the logout controller.
Basically you can set the cookie yourself and set the expires manually
res.cookie('userSession', {
items: [1, 2, 3]
}, {
expires: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
httpOnly: true
})

how to make laravel auto redirect a user when the session has expired

I am working on a project using laravel 4.2. I want when the user is logged in their session will expire in 60 mins and laravel will auto redirect the user without them interacting with web application. however, I am not seeing anything in the laravel docs that explains how to do this approach. If you can assist me with this problem that would be much help thanks.
Well. You should make an AJAX call to the server each minute, and then process the request:
setInterval(function(){
$.get("user/timespan");
}, 6000); // send request each 60 seconds
Now in laravel's controller you put:
class User extends Controller
{
public function timespan() // here we receive AJAX request
{
$allowed_time = 60 * 60; // seconds
$current = time(); // we register current time
$old_time = Session::get("user_loggedin); // we registered this session when user logged in
if( ($current - $old_time) > ($allowed_time) )
{
// do the redirection, since it has stayed more than 60 minutes
}
}
}
The above solution basically works, but you can set Session time limit to 60 minutes in Laravel, and then send the above ajax request and check for the availability of the session. This saves your life from re-computing the 60-minutes duration.
I think the best solution of this is using cookies. When you put session, also add cookie then check the cookie.
When logged;
Sesion::put("user_data",$user_data); // or
Auth:attempt($credentials);
Cookie::queue("session_control","value",60);
And When you want to check cookie (like on filter);
if(!Cookie::has()){
Session::forget('user_data'); //or
Auth::logout();
}

Resources