Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update auth.php #46

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 109 additions & 20 deletions auth.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

function generateToken($subject, $audience, $issuer, $time, $ttl, $algorithm, $secret)
//this file should be served from https://api.example.com/auth.php
function generateToken($subject, $user, $audience, $issuer, $time, $ttl, $algorithm, $secret)
{
$algorithms = array(
'HS256' => 'sha256',
Expand All @@ -16,6 +16,8 @@ function generateToken($subject, $audience, $issuer, $time, $ttl, $algorithm, $s
$token = array();
$token[0] = rtrim(strtr(base64_encode(json_encode((object) $header)), '+/', '-_'), '=');
$claims['sub'] = $subject;
$claims['email'] = $user->email; // added email to claims
$claims['role'] = $user->role; // added role to claims
$claims['aud'] = $audience;
$claims['iss'] = $issuer;
$claims['iat'] = $time;
Expand Down Expand Up @@ -48,10 +50,13 @@ function serve($file)
echo file_get_contents($file);
}

function handleGet($config, $session)
function handleGet($config, $session, $logout, $error)
{
if (empty($session)) {
serve($config['login']);
if ($error) {
redirect($config['loginError']); // redirect (instead of serving an html page) to login application with error parameter set to=1 in case of failed login (used to display error message)
}
if (empty($session) || $logout) {
redirect($config['login']); // redirect (instead of serving an html page) to login application in case of missing token
} else {
redirect(generateTokenUrl($config, $session));
}
Expand All @@ -62,6 +67,11 @@ function getSecure()
return isset($_SERVER['HTTPS']) && !in_array(strtolower($_SERVER['HTTPS']), array('off', 'no'));
}

function getHost() // get host name, used to set the instance server name as issuer
{
return $_SERVER['HTTP_HOST'];
}

function getFullUrl()
{
return (getSecure() ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
Expand All @@ -70,26 +80,29 @@ function getFullUrl()
function generateTokenUrl($config, $session)
{
$time = getConfig($config, 'time', time());
$ttl = getConfig($config, 'ttl', 5);
$ttl = getConfig($config, 'ttl', 3600);
$algorithm = getConfig($config, 'algorithm', 'HS256');
$secret = getConfig($config, 'secret', '');
$subject = $session['username'];
$subject = $session['user']->uuid;
$user = $session['user'];
$audience = $config['audience'];
$issuer = getFullUrl();
$token = generateToken($subject, $audience, $issuer, $time, $ttl, $algorithm, $secret);
$issuer = getHost();
$token = generateToken($subject, $user, $audience, $issuer, $time, $ttl, $algorithm, $secret);
$redirectUri = getConfig($config, 'redirectUri', '');
return $redirectUri . '#access_token=' . $token;
}

function handlePost($config, &$session, $username, $password)
{
$validate = getConfig($config, 'validate', function ($username, $password) {return false;});
$validate = getConfig($config, 'validate', function ($username, $password) {
return false;
});
$valid = call_user_func($validate, $username, $password);
if (!$valid) {
serve($config['login']);
if (!$valid['success']) {
redirect($config['loginError']); // added redirect to login page with error parameter set to=1 in case of failed login (used to display error message)
} else {
session_regenerate_id();
$session['username'] = $username;
$session['user'] = $valid['payload'];
redirect(generateTokenUrl($config, $session));
}
}
Expand All @@ -107,9 +120,14 @@ function getConfig($config, $key, $default)
function main($config)
{
session_start();
$logout = isset($_GET['logout']) ? $_GET['logout'] : '0'; // added logout parameter as logout flag to unset the php session
$error = isset($_GET['error']) ? $_GET['error'] : '0'; // added error parameter as error flag to enter in error state
$clientId = isset($_GET['client_id']) ? $_GET['client_id'] : 'default';
$audience = isset($_GET['audience']) ? $_GET['audience'] : 'default';
$redirectUri = isset($_GET['redirect_uri']) ? $_GET['redirect_uri'] : '';
if ($logout) {
session_unset(); // unset the php session
}
if (isset($config[$clientId][$audience])) {
$config = $config[$clientId][$audience];
$config['clientId'] = $clientId;
Expand All @@ -121,7 +139,7 @@ function main($config)
if (isset($config['redirectUri'])) {
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
handleGet($config, $_SESSION);
handleGet($config, $_SESSION, $logout, $error); //added logout and error parameters
break;
case 'POST':
handlePost($config, $_SESSION, $_POST['username'], $_POST['password']);
Expand All @@ -135,15 +153,86 @@ function main($config)
}
}

//implementation examples
main([
'default' => [
'api.php' => [
'default' => [ // client_id
'example1' => [ // audience1
'secret' => 'someVeryLongPassPhraseChangeMe',
'login' => 'login.html',
'redirects' => 'http://localhost/vanilla.html',
'validate' => function ($username, $password) {
return $username == 'admin' && $password == 'admin';
'login' => 'https://login.example1.com/', // redirection to login application in case of missing token
'loginError' => 'https://login.example1.com?error=1', // redirection to login application with error parameter set to=1 in case of failed login (used to display error message)
'redirects' => 'https://app.example1.com', // redirects to application in case of successful login
'validate' => function ($username, $password) { // validation of username and password, this example uses api.php and dbauth middleware
$url = "api.example1.com/authapi.php/login"; // this instance of api.php is configured to use dbauth middleware
$data = array('username' => $username, 'password' => $password);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$resp = file_get_contents($url, false, $context); // retreived user data from authapi.php
preg_match('/([0-9])\d+/', $http_response_header[0], $matches); // response code from authapi.php
$responsecode = intval($matches[0]);
return array('success' => ($responsecode == 200), 'payload' => $resp); // return success status and user data, user data will be used to generate the jwt token
},
],
'example2' => [ // audience2
'secret' => 'someVeryLongPassPhraseChangeMe',
'login' => 'https://login.example2.com/', // redirection to login application in case of missing token
'loginError' => 'https://login.example2.com?error=1', // redirection to login application with error parameter set to=1 in case of failed login (used to display error message)
'redirects' => 'https://app.example2.com', // redirects to application in case of successful login
'validate' => function ($username, $password) { // validation of static username and password, with fixed payload
$valid = $username == 'company_admin_account' && $password == 'password';
$response = array(
'success' => ($valid == true),
'payload' => json_decode('{
"uuid": "[email protected]",
"email": "[email protected]",
"role": "admin"
}')
);
return $response;
}
]
],
'development_team_example' => [ // client_id
'developer1' => [ // audience1 - developer1
'secret' => 'someVeryLongPassPhraseChangeMe',
'login' => 'https://login.devel.example1.com/', // redirection to login application in case of missing token
'loginError' => 'https://login.devel.example1.com?error=1', // redirection to login application with error parameter set to=1 in case of failed login (used to display error message)
'redirects' => 'http://localhost:8080/', // redirects to localhost development environment
'validate' => function ($username, $password) { // validation of static username and password, with fixed payload
$valid = $username == 'developer1' && $password == 'password';
$response = array(
'success' => ($valid == true),
'payload' => json_decode('{
"uuid": "developer1",
"email": "[email protected]",
"role": "developer"
}')
);
return $response;
}
],
'developer2' => [ // audience2 - developer2
'secret' => 'someVeryLongPassPhraseChangeMe',
'login' => 'https://login.devel.example2.com/', // redirection to login application in case of missing token
'loginError' => 'https://login.devel.example2.com?error=1', // redirection to login application with error parameter set to=1 in case of failed login (used to display error message)
'redirects' => 'http://localhost:8081/', // redirects to application in case of successful login
'validate' => function ($username, $password) { // validation of static username and password, with fixed payload
$valid = $username == 'developer2' && $password == 'password';
$response = array(
'success' => ($valid == true),
'payload' => json_decode('{
"uuid": "developer2",
"email": "[email protected]",
"role": "developer"
}')
);
return $response;
}
]
]
]);
31 changes: 31 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!-- this file should be served from https://app.example.com -->
<!DOCTYPE html>
<html>

<head>
<title>JWT EXAMPLE APP</title>
</head>

<body>
<script>
var xhr = new XMLHttpRequest();
xAuth = xhr.getResponseHeader('X-Authorization');

var token = xAuth.split(' ')[1];

if (!token) {
window.location.href = 'https://api.example.com/auth.php?audience=example&client_id=example&redirect_uri=https://app.example.com/';
}

// Logout button
var logoutBtn = document.createElement('button');
logoutBtn.innerHTML = 'Logout';
logoutBtn.onclick = function () {
window.location.href = 'https://login.example.com?logout=1';
};
document.body.appendChild(logoutBtn);

</script>
</body>

</html>
73 changes: 68 additions & 5 deletions login.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,68 @@
<form method="post">
<input name="username" value="admin"/>
<input name="password" value="admin"/>
<input type="submit" value="ok">
</form>
<!-- this file should be served from login.example.com -->
<!DOCTYPE html>
<html>

<head>
<title>Login</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function () {
const urlParams = new URLSearchParams(window.location.search);
const logout = urlParams.get('logout');
const error = urlParams.get('error');

if (logout) {
$.ajax({
url: 'https://api.example.com/authapi.php/logout',
method: 'GET',
success: function (response) {
// Clear any local session data here
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error: ' + textStatus, errorThrown);
}
});
}

if (error) {
$('#error-message').text(error);
}
$('#login-form').submit(function (event) {
event.preventDefault();
var username = $('#username').val();
var password = $('#password').val();
$.ajax({
url: 'https://api.example.com/auth.php?audience=example&client_id=example&redirect_uri=https://app.example.com/',
method: 'POST',
data: {
username: username,
password: password
}
});
});
});
</script>
</head>

<body>
<h1>Login</h1>
<form id="login-form">
<label for="username">Username:</label>
<input type="text" id="username" name="username"><br><br>
<label for="password">Password:</label>
<input type="password" id="password" name="password"><br><br>
<input type="submit" value="Login">
</form>
<p id="error-message"></p>
</body>

</html>


authUrl: "https://jwt.devel.tourismapp.it/",
auth: {
seg1: 'https://jwt.devel.tourismapp.it?audience=',
seg2: '&response_type=token&client_id=',
seg3: '&redirect_uri=https://',
seg4: '.tourismapp.it/'
},