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
})
Related
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
This question already has answers here:
Accessing Session Using ASP.NET Web API
(13 answers)
Closed 3 years ago.
In my Web api when a user login successfully I set session with some values like
HttpContext.Session.SetObject("CurrentUserID", user.Id);
HttpContext.Session.SetObject("CurrentUserRoles",user.Roles);
and just return token and some values to save in cookie
return Ok(new
{
Id = user.Id,
Username = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
Token = tokenString,
role = user.Roles
});
But when the client hit api action which has this line
List<string> userRolesList = HttpContext.Session.GetObject<List<string>>("CurrentUserRoles");
Then always get null value even I have added session inside Startup >Configure
like
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
and ConfigureService also
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds( 60 * 60);
options.Cookie.HttpOnly = true;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
but does work still... Please help.
HTTP is a stateless protocol. Sessions are fake state, enabled by both a server-side and client-side component. The client-side component is a cookie: specifically a Set-Cookie response header. In order for the session to be restored on the next request, the value of this Set-Cookie response header must be sent back via the Cookie request header with each request. A web browser (the client) will do all this automatically, including persisting the cookie locally. However, a thin client like HttpClient, Postman, etc. will not. You would need to independently persist the cookie from the response header and then attach it to each request via the Cookie header in order to maintain the session between requests.
That said, this is a major reason why APIs typically do not, and honestly should not make use of sessions. It's simply a pattern that doesn't make much sense in an API context, and only adds a potential point of failure, since clients must pay attention to the cookie headers, and take manual actions to handle the cookies.
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();
}
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
I feel like this has to be buried somewhere in the documentation, but I can't find it.
How do you close or end or kill (whatever) a session in ExpressJS?
Express 4.x Updated Answer
Session handling is no longer built into Express. This answer refers to the standard session module: https://github.com/expressjs/session
To clear the session data, simply use:
req.session.destroy();
The documentation is a bit useless on this. It says:
Destroys the session, removing req.session, will be re-generated next request.
req.session.destroy(function(err) {
// cannot access session here
})
This does not mean that the current session will be re-loaded on the next request. It means that a clean empty session will be created in your session store on next request. (Presumably the session ID isn't changing, but I have not tested that.)
Never mind, it's req.session.destroy();
The question didn't clarify what type of session store was being used. Both answers seem to be correct.
For cookie based sessions:
From http://expressjs.com/api.html#cookieSession
req.session = null // Deletes the cookie.
For Redis, etc based sessions:
req.session.destroy // Deletes the session in the database.
Session.destroy(callback)
Destroys the session and will unset the req.session property. Once complete, the callback will be invoked.
↓ Secure way ↓ ✅
req.session.destroy((err) => {
res.redirect('/') // will always fire after session is destroyed
})
↓ Unsecure way ↓ ❌
req.logout();
res.redirect('/') // can be called before logout is done
use,
delete req.session.yoursessionname;
From http://expressjs.com/api.html#cookieSession
To clear a cookie simply assign the session to null before responding:
req.session = null
To end a server-side session
https://github.com/expressjs/session#sessiondestroycallback
req.session.destroy(function(err) {
// cannot access session here
})
Note, this is essentially a wrapper around delete req.session as seen in the source code:
https://github.com/expressjs/session/blob/master/session/session.js
defineMethod(Session.prototype, 'destroy', function destroy(fn) {
delete this.req.session;
this.req.sessionStore.destroy(this.id, fn);
return this;
});
To end a cookie-session
https://github.com/expressjs/cookie-session#destroying-a-session
req.session = null;
req.session.destroy();
The above did not work for me so I did this.
req.session.cookie.expires = new Date().getTime();
By setting the expiration of the cookie to the current time, the session expired on its own.
You can retrieve the id of a session using req.session.id or req.sessionID and then pass it to req.sessionStore.destroy method like so:
const sessionID = req.session.id;
req.sessionStore.destroy(sessionID, (err) => {
// callback function. If an error occurs, it will be accessible here.
if(err){
return console.error(err)
}
console.log("The session has been destroyed!")
})
Reference to the req.sessionStore.destroy method.
As mentioned in several places, I'm also not able to get the req.session.destroy() function to work correctly.
This is my work around .. seems to do the trick, and still allows req.flash to be used
req.session = {};
If you delete or set req.session = null; , seems then you can't use req.flash