# Session Auth
Version support
This experiment supports v2.4.1
upwards.
# What are we building?
Although most web apps mostly rely on APIs and token/OAuth, the practice of using built in sessions for authentication certainly hasn't faded out.
In this experiment, we'll be looking at how to create logins, signups and user updates with Leaf v2.4.1. We'll be relying on the new session support in the auth package and we'll also be using blade for our templating.
Detailed Explanation: Session authentication
Session based authentication is one in which the user state is stored on the server’s memory.
Read the full article here (opens new window)
Detailed Explanation: Templating engines
For the sake of our tutorial, let's say that templating engines are a way of outputting code which allows us separate our logic from our views. There are many template engines out there, blade, twig, smarty and more.
According to expressjs.com:
a template engine enables you to use static template files in your application. At runtime, the template engine replaces variables in a template file with actual values, and transforms the template into an HTML file sent to the client. This approach makes it easier to design an HTML page.
# Building Our Login
First of all, we need a route to handle our login screen. We'll use leaf's core router for this. We'll also be using leaf blade as our templating engine.
require __DIR__ . "/vendor/autoload.php";
$app = new Leaf\App;
// show login page
$app->get("/auth/login", function() use($app) {
$app->blade->render("login");
});
// login logic
$app->post("/auth/login", function() use($app) {
// logic here
});
$app->run();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Next we'll define our blade view, login.blade.php
:
<section>
<h1>Login</h1>
<p>
Sign into Leaf APP
</p>
</section>
<form action="/auth/login" method="post">
<div class="form-group">
<input class="form-control" type="text" name="username" placeholder="username" value="{{ $username ?? '' }}">
<small class="mb-1">{{ $errors['username'] ?? $errors['auth'] ?? null }}</small>
</div>
<div class="form-group">
<input class="form-control" type="password" name="password" placeholder="password" value="{{ $password ?? '' }}">
<small class="mb-1">{{ $errors['password'] ?? null }}</small>
</div>
<button class="btn btn-primary">Login</button>
</form>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Before we jump into the code, let's talk about the processes involved. When a user logs in, a new session is created for them. This session holds the user and the session tracker logs assigned by Leaf Auth. We can check the user's logged in state to load a page or redirect.
To set all this up with Leaf, all we need is one extra word: true
. We can pass true into Leaf Auth on init to switch to session authentication instead of JWT.
$auth = new Leaf\Auth(true);
So in the logic side of our code, we can simply pass $auth
into the function with use
.
require __DIR__ . "/vendor/autoload.php";
$app = new Leaf\App;
$auth = new Leaf\Auth(true);
$app->get("/auth/login", function() use($app) {
$app->blade->render("login");
});
$app->post("/auth/login", function() use($app, $auth) {
// logic here
});
2
3
4
5
6
7
8
9
10
11
12
Now we can focus on the login logic. If you've used auth before in previous versions, adding session support literally changed nothing about the syntax, so you can still comfortably create your logins in the very same way.
$auth->login("users", [
"username" => $username,
"password" => $password
]);
2
3
4
Even the error handling works the same way too:
$user = $auth->login("users", [
"username" => $username,
"password" => $password
]);
if (!$user) {
// an error happened here, you can display
// them on your template. The errors can be
// grabbed with $auth->errors()
}
2
3
4
5
6
7
8
9
10
On a successful login, login
will redirect the user to GUARD_HOME
which is simply the homepage route. This route can be configured using the config method.
$auth->config("GUARD_HOME", "/dashboard");
Putting it all together, we can have something like this:
// get username and password submitted from login form
list($username, $password) = array_values($app->request()->get(["username", "email"]));
$auth->config("GUARD_HOME", "/dashboard");
// attempt a login
$user = $auth->login("users", [
"username" => $username,
"password" => $password
]);
// if there's a problem with credentials or system
if (!$user) {
// render login page
return $app->blade->render("login", [
// pass in errors and credentials
"errors" => $auth->errors(),
"username" => $username,
"password" => $password,
]);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
As you can see nothing has changed in the login implementation even though a ton of new features have been added. There's one last thing though: when an already logged in user tries to go to the login page, we want to redirect to GUARD_HOME
.
This means we have to check the session to find if the user is logged in or not, redirect if the user is logged in and maintain the page if the user isn't. Leaf makes this simple as well as it provides a guard
method.
$auth->guard("guest");
This tells leaf that the page is a guest page and should not be accesible when the user is logged in. Putting all what we've discussed together should look like this:
require __DIR__ . "/vendor/autoload.php";
$app = new Leaf\App;
$auth = new Leaf\Auth(true);
// connect to db. You can use autoConnect too
$auth->connect("host", "user", "password", "dbName");
$auth->config("GUARD_HOME", "/dashboard");
$app->get("/auth/login", function() use($app) {
$auth->guard("guest");
$app->blade->render("login");
});
$app->post("/auth/login", function() use($app, $auth) {
$auth->guard("guest");
list($username, $password) = array_values($app->request()->get(["username", "email"]));
// attempt a login
$user = $auth->login("users", [
"username" => $username,
"password" => $password
]);
// if there's a problem with credentials or system
if (!$user) {
// render login page
return $app->blade->render("login", [
// pass in errors and credentials
"errors" => $auth->errors(),
"username" => $username,
"password" => $password,
]);
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Building Our Register
Registration involves saving the user in the database. From there we can immedietely initialize a session or go to the GUARD_LOGIN
page so the user signs in. Since we've already configured Leaf Auth, let's just jump right into the code.
$app->post("/auth/register", function() use($app, $auth) {
$auth->guard("guest");
$credentials = $app->request()->get(["username", "email", "password"]);
// automatically login immedietely the user is created
$auth->config("SESSION_ON_REGISTER", true);
$user = $auth->register("users", $credentials, [
"username", "email"
]);
if (!$user) {
return $app->blade->render("register", array_merge(
["errors" => array_merge($auth->errors()],
request(["username", "email", "password"]))
);
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Here, we're creating a handler for our register method, getting the request data we need and saving it in the database using register
. You might have noticed the 3rd parameter, ["username", "email"]
. This just makes sure that the same username and email don't already exist in the database. Leaf literally does everything for you. We can have a template like this:
<form action="/auth/register" method="post">
<div class="form-group">
<input class="form-control" type="text" name="username" placeholder="username" value="{{ $username ?? '' }}">
<p>{{ $errors['username'] ?? $errors['auth'] ?? null }}</p>
</div>
<div class="form-group">
<input class="form-control" type="email" name="email" placeholder="email" value="{{ $email ?? '' }}">
<p>{{ $errors['email'] ?? $errors['auth'] ?? null }}</p>
</div>
<div class="form-group">
<input class="form-control" type="password" name="password" placeholder="password" value="{{ $password ?? '' }}">
<p>{{ $errors['password'] ?? null }}</p>
</div>
<button class="btn btn-primary">Register</button>
</form>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
And with this we've successfully created our register functionality. Read the auth docs for more info on session auth.
Experiment by Mychi Darko