aboutsummaryrefslogtreecommitdiff
path: root/content/blog/2020-08-29-php-auth-flow.org
blob: 2e5cf5c8be9738cbd5e650171840bf675c543c87 (plain) (blame)
1
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#+title: PHP Authentication Flow
#+date: 2020-08-29
#+description: Learn how to establish and maintain a basic user authentication flow in PHP.
#+filetags: :dev:

* Introduction
When creating websites that will allow users to create accounts, the
developer always needs to consider the proper authentication flow for
their app. For example, some developers will utilize an API for
authentication, some will use OAuth, and some may just use their own
simple database.

For those using pre-built libraries, authentication may simply be a
problem of copying and pasting the code from their library's
documentation. For example, here's the code I use to authenticate users
with the Tumblr OAuth API for my Tumblr client, Vox Populi:

#+begin_src php
// Start the session
session_start();

// Use my key/secret pair to create a new client connection
$consumer_key = getenv('CONSUMER_KEY');
$consumer_secret = getenv('CONSUMER_SECRET');
$client = new Tumblr\API\Client($consumer_key, $consumer_secret);
$requestHandler = $client->getRequestHandler();
$requestHandler->setBaseUrl('https://www.tumblr.com/');

// Check the session and cookies to see if the user is authenticated
// Otherwise, send user to Tumblr authentication page and set tokens from Tumblr's response

// Authenticate client
$client = new Tumblr\API\Client(
    $consumer_key,
    $consumer_secret,
    $token,
    $token_secret
);
#+end_src

However, developers creating authentication flows from scratch will need
to think carefully about when to make sure a web page will check the
user's authenticity.

In this article, we're going to look at a simple authentication flow
using a MySQL database and PHP.

* Creating User Accounts
The beginning to any type of user authentication is to create a user
account. This process can take many formats, but the simplest is to
accept user input from a form (e.g., username and password) and send it
over to your database. For example, here's a snippet that shows how to
get username and password parameters that would come when a user submits
a form to your PHP script.

*Note*: Ensure that your password column is large enough to hold the
hashed value (at least 60 characters or longer).

#+begin_src php
// Get the values from the URL
$username = $_POST['username'];
$raw_password = $_POST['password'];

// Hash password
// password_hash() will create a random salt if one isn't provided, and this is generally the easiest and most secure approach.
$password = password_hash($raw_password, PASSWORD_DEFAULT);

// Save database details as variables
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";

// Create connection to the database
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
  die("Connection failed: " . $conn->connect_error);
}

$sql = "INSERT INTO users (username, password)
VALUES ('$username', '$password')";

if ($conn->query($sql) === TRUE) {
  echo "New record created successfully";
} else {
  echo "Error: " . $sql . "<br>" . $conn->error;
}

$conn->close();
#+end_src

** Validate Returning Users
To be able to verify that a returning user has a valid username and
password in your database is as simple as having users fill out a form
and comparing their inputs to your database.

#+begin_src php
// Query the database for username and password
// ...

if(password_verify($password_input, $hashed_password)) {
    // If the input password matched the hashed password in the database
    // Do something, log the user in.
}

// Else, Redirect them back to the login page.
...
#+end_src

* Storing Authentication State
Once you've created the user's account, now you're ready to initialize
the user's session. *You will need to do this on every page you load
while the user is logged in.** To do so, simply enter the following code
snippet:

#+begin_src php
session_start();
#+end_src

Once you've initialized the session, the next step is to store the
session in a cookie so that you can access it later.

#+begin_src php
setcookie(session_name());
#+end_src

Now that the session name has been stored, you'll be able to check if
there's an active session whenever you load a page.

#+begin_src php
if(isset(session_name())) {
    // The session is active
}
#+end_src

** Removing User Authentication
The next logical step is to give your users the option to log out once
they are done using your application. This can be tricky in PHP since a
few of the standard ways do not always work.

#+begin_src php
// Initialize the session.
// If you are using session_name("something"), don't forget it now!
session_start();

// Delete authentication cookies
unset($_COOKIE[session_name()]);
setcookie(session_name(), "", time() - 3600, "/logged-in/");
unset($_COOKIE["PHPSESSID"]);
setcookie("PHPSESSID", "", time() - 3600, "/logged-in/");

// Unset all of the session variables.
$_SESSION = array();
session_unset();

// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
if (ini_get("session.use_cookies")) {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
}

// Finally, destroy the session.
session_destroy();
session_write_close();

// Go back to sign-in page
header('Location: https://example.com/logged-out/');
die();
#+end_src

* Wrapping Up
Now you should be ready to begin your authentication programming with
PHP. You can create user accounts, create sessions for users across
different pages of your site, and then destroy the user data when
they're ready to leave.

For more information on this subject, I recommend reading the
[[https://www.php.net/][PHP Documentation]]. Specifically, you may want
to look at [[https://www.php.net/manual/en/features.http-auth.php][HTTP
Authentication with PHP]],
[[https://www.php.net/manual/en/book.session.php][session handling]],
and [[https://www.php.net/manual/en/function.hash.php][hash]].