Skip to content

Commit e98a831

Browse files
kmazariegosKarla Mazariegos
andauthored
Update MFA totp factor enroll flow (#30)
* Update MFA totp factor enroll flow * Update MFA totp factor enroll flow --------- Co-authored-by: Karla Mazariegos <[email protected]>
1 parent 05a6597 commit e98a831

File tree

8 files changed

+473
-326
lines changed

8 files changed

+473
-326
lines changed

php-mfa-example/router.php

Lines changed: 123 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
<?php
22

3-
require __DIR__ . "/vendor/autoload.php";
4-
3+
require __DIR__ . "/vendor/autoload.php";
4+
error_reporting(E_ALL ^ E_WARNING);
55
use Twig\Environment;
66
use Twig\Loader\FilesystemLoader;
77

8+
include './variables.php';
9+
10+
// Setup html templating library
11+
$loader = new FilesystemLoader(__DIR__ . '/templates');
12+
$twig = new Environment($loader);
13+
814
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
915
$dotenv->load();
1016

1117
//Set API Key, ClientID, and Connection
1218
$WORKOS_API_KEY = $_ENV['WORKOS_API_KEY'];
1319
$WORKOS_CLIENT_ID = $_ENV['WORKOS_CLIENT_ID'];
1420

15-
// Setup html templating library
16-
$loader = new FilesystemLoader(__DIR__ . '/templates');
17-
$twig = new Environment($loader);
18-
1921
// Configure WorkOS with API Key and Client ID
2022
\WorkOS\WorkOS::setApiKey($WORKOS_API_KEY);
2123
\WorkOS\WorkOS::setClientId($WORKOS_CLIENT_ID);
@@ -37,6 +39,22 @@ function httpNotFound()
3739
return true;
3840
}
3941

42+
function objectToArray($obj) {
43+
$arr = [];
44+
$reflection = new ReflectionClass($obj);
45+
$properties = $reflection->getProperties();
46+
foreach ($properties as $property) {
47+
$name = $property->getName();
48+
$property->setAccessible(true);
49+
$value = $property->getValue($obj);
50+
if (is_object($value)) {
51+
$value = objectToArray($value);
52+
}
53+
$arr[$name] = $value;
54+
}
55+
return $arr;
56+
}
57+
4058
// Routing
4159
switch (strtok($_SERVER["REQUEST_URI"], "?")) {
4260
case (preg_match("/\.css$/", $_SERVER["REQUEST_URI"]) ? true : false):
@@ -58,73 +76,99 @@ function httpNotFound()
5876
return httpNotFound();
5977

6078
// '/' route is what will be the home page, allow users to get started creating an MFA factor.
61-
6279
case ("/"):
6380
session_start();
81+
$_SESSION['factorArray'];
82+
echo $twig->render("index.html.twig", ['factors' => $_SESSION['factorArray']]);
6483

84+
return true;
85+
86+
case ("/clear_session"):
87+
session_start();
88+
$_SESSION['factorArray'] = [];
89+
Redirect('/', false);
90+
echo $twig->render("index.html.twig");
91+
return true;
92+
93+
case ("/enroll_factor"):
94+
session_start();
6595
echo $twig->render("enroll_factor.html.twig");
66-
6796
return true;
68-
69-
// '/factor_details' enrolls and displays the factor that was selected in the previous step. Allows user
70-
// to use to authenticate the factor
71-
72-
case ("/factor_detail"):
97+
98+
case ("/enroll_sms_factor"):
7399
session_start();
74-
75-
$factorType = $_POST['type'];
76-
77-
if (isset($_POST['phone_number'])):
78-
$phoneNumber = $_POST['phone_number'];
79-
else :
80-
$phoneNumber = null;
81-
endif;
82-
83-
if (isset($_POST['totp_issuer'])) {
84-
$totpIssuer = $_POST['totp_issuer'];
100+
$factor_type = $_POST["type"];
101+
$new_factor;
102+
if (!isset($_SESSION['factorArray'])) {
103+
$_SESSION['factorArray'] = array();
85104
}
86-
87-
if (isset($_POST['totp_user'])) {
88-
$totpUser = $_POST['totp_user'];
89-
}
90-
91-
if ($factorType == "sms") {
92-
$newFactor = (new \WorkOS\MFA()) -> enrollFactor($factorType, null, null, $phoneNumber);
93-
$phoneNumber = $newFactor->sms['phone_number'];
94-
// $environment = $newFactor->environmentId;
95-
$type = $newFactor->type;
105+
106+
if ($factor_type == "sms") {
107+
$factor_type = "sms";
108+
$phoneNumber = $_POST["phone_number"];
109+
$USnumber = "+1" . $phoneNumber;
110+
$new_factor = (new \WorkOS\MFA())
111+
->enrollFactor(
112+
type: $factor_type,
113+
phoneNumber: $USnumber
114+
);
96115
}
116+
$data = objectToArray($new_factor);
117+
array_push($_SESSION['factorArray'], $data);
118+
echo $twig->render("index.html.twig", ['factors' => $_SESSION['factorArray']]);
119+
return true;
97120

98-
if ($factorType == "totp") {
99-
$newFactor = (new \WorkOS\MFA()) -> enrollFactor($factorType, $totpIssuer, $totpIssuer, null);
100-
$type = $newFactor->type;
101-
// $environment = $newFactor->environmentId;
102-
$qrCode = $newFactor->totp['qr_code'];
121+
case ('/enroll_totp_factor'):
122+
session_start();
123+
if (!isset($_SESSION['factorArray'])) {
124+
$_SESSION['factorArray'] = array();
103125
}
104-
105-
if (!isset($_SESSION['factor_list'])) {
106-
$_SESSION['factor_list'] = array();
107-
array_push($_SESSION['factor_list'], $newFactor);
108-
} else {
109-
array_push($_SESSION['factor_list'], $newFactor);
126+
127+
$input = json_decode(file_get_contents('php://input'), true);
128+
$type = $input['type'];
129+
$issuer = $input['issuer'];
130+
$user = $input['user'];
131+
$enrolledFactorObj = (new \WorkOS\MFA())->enrollFactor(
132+
type: $type, totpIssuer: $issuer, totpUser: $user
133+
);
134+
$enrolledFactor = objectToArray($enrolledFactorObj);
135+
136+
$qr_code = $enrolledFactor['raw']['totp']['qr_code'];
137+
$object = $enrolledFactor['raw']['object'];
138+
$id = $enrolledFactor['raw']['id'];
139+
$created_at = $enrolledFactor['raw']['created_at'];
140+
$updated_at = $enrolledFactor['raw']['updated_at'];
141+
$type = $enrolledFactor['raw']['type'];
142+
143+
$newFactor = array(
144+
'object' => $object,
145+
'id' => $id,
146+
'created_at' => $created_at,
147+
'updated_at' => $updated_at,
148+
'type' => $type
149+
);
150+
151+
array_push($_SESSION['factorArray'], $enrolledFactor);
152+
echo json_encode($qr_code);
153+
return true;
154+
155+
case ("/factor_detail"):
156+
session_start();
157+
$id = $_GET['id'];
158+
$factor = null;
159+
foreach ($_SESSION['factorArray'] as $f) {
160+
$item = $f['values']['id'];
161+
if($item === $id){
162+
$factor = $f;
163+
}
110164
}
111-
112-
$authenticationFactorId = $newFactor->id;
113-
$createdAt = $newFactor->createdAt;
114-
115-
$_SESSION['authentication_factor_id'] = $authenticationFactorId;
116-
117-
if ($type == 'sms'):
118-
echo $twig->render("factor_detail.html.twig", ['factor_list' => json_encode($_SESSION['factor_list']), 'phone_number' => $phoneNumber, 'type' => $type, 'authentication_factor_id' => $authenticationFactorId, 'code' => "{{code}}", 'created_at' => $createdAt]);
119-
elseif ($type == 'totp'):
120-
echo $twig->render("factor_detail.html.twig", ['factor_list' => json_encode($_SESSION['factor_list']), 'type' => $type, 'authentication_factor_id' => $authenticationFactorId, 'qr_code' => $qrCode, 'code' => "{{code}}", 'created_at' => $createdAt]);
121-
endif;
122-
165+
$_SESSION['current_factor'] = $factor;
166+
$_SESSION['id'] = $id;
167+
echo $twig->render("factor_detail.html.twig", ['factor' => $_SESSION['current_factor'], "title" => 'Factor Detail']);
123168
return true;
124169

125-
// '/challenge_factor' will allow the user to select to challenge the factor they created by inputting
126-
// what should be the correct code
127-
170+
// '/challenge_factor' will allow the user to select to challenge the factor they created by inputting
171+
// what should be the correct code
128172
case ("/challenge_factor"):
129173
session_start();
130174
echo $twig->render("challenge_factor.html.twig");
@@ -135,34 +179,39 @@ function httpNotFound()
135179
$smsMessage = null;
136180
endif;
137181

138-
$challengeFactor = (new \WorkOS\MFA()) -> challengeFactor($_SESSION['authentication_factor_id'], $smsMessage);
139-
140-
$_SESSION['authentication_challenge_id'] = $challengeFactor->id;
182+
$challengeFactor = (new \WorkOS\MFA()) -> challengeFactor($_SESSION['id'], $smsMessage);
183+
$challengeFactorArr = objectToArray($challengeFactor);
184+
$_SESSION['authentication_challenge_id'] = $challengeFactorArr['values']['id'];
185+
return true;
141186

187+
case ("/challenge_success"):
188+
session_start();
189+
echo $twig->render("challenge_success.html.twig",['title' => 'Challenge Success']);
142190
return true;
143191

144192
// 'challenge_success' will display whether or not the user successfully passed the challenge, and allow a return to
145193
// the home page.
146194

147-
case ("/challenge_success"):
195+
case ("/verify_factor"):
148196
session_start();
149197

150-
if (isset($_POST['code-1'])):
198+
if (isset($_POST['code-1'])){
151199
$codeArray = [];
152200
foreach($_POST as $key => $value) {
153201
array_push($codeArray, $value);
154202
}
155203
$code = implode($codeArray);
156-
157-
else:
204+
}else{
158205
$code = null;
159-
endif;
160-
161-
$verifyFactor = (new \WorkOS\MFA()) -> verifyFactor($_SESSION['authentication_challenge_id'], $code);
162-
163-
$valid = json_encode($verifyFactor->valid);
164-
165-
echo $twig->render("challenge_success.html.twig", ['authentication_factor_id' => json_encode($_SESSION['authentication_factor_id']), 'valid' => $valid]);
206+
}
207+
$verifyFactor = (new \WorkOS\MFA()) -> verifyChallenge($_SESSION['authentication_challenge_id'], $code);
208+
$verifyFactorArr = objectToArray($verifyFactor);
209+
$valid = $verifyFactorArr['values']['valid'];
210+
$authFactor = $_SESSION['current_factor'];
211+
$expires_at = $verifyFactorArr['values']["challenge"]['expires_at'];
212+
$created_at = $verifyFactorArr['values']["challenge"]['created_at'];
213+
echo $twig->render("challenge_success.html.twig", ['authentication_factor_id' => $authFactor, 'valid' => $valid, 'created_at' => $created_at, 'updated_at' => $expires_at]);
214+
return true;
166215

167216
// no break
168217
default:

0 commit comments

Comments
 (0)