Single Sign-On for PHP (Ajax compatible)

Overview

jasny-banner

Single Sign-On for PHP (Ajax compatible)

PHP Scrutinizer Code Quality Code Coverage Packagist Stable Version Packagist License

Jasny SSO is a relatively simply and straightforward solution for single sign on (SSO).

With SSO, logging into a single website will authenticate you for all affiliate sites. The sites don't need to share a toplevel domain.

How it works

When using SSO, when can distinguish 3 parties:

  • Client - This is the browser of the visitor
  • Broker - The website which is visited
  • Server - The place that holds the user info and credentials

The broker has an id and a secret. These are known to both the broker and server.

When the client visits the broker, it creates a random token, which is stored in a cookie. The broker will then send the client to the server, passing along the broker's id and token. The server creates a hash using the broker id, broker secret and the token. This hash is used to create a link to the user's session. When the link is created the server redirects the client back to the broker.

The broker can create the same link hash using the token (from the cookie), the broker id and the broker secret. When doing requests, it passes that hash as a session id.

The server will notice that the session id is a link and use the linked session. As such, the broker and client are using the same session. When another broker joins in, it will also use the same session.

For a more in depth explanation, please read this article.

How is this different from OAuth?

With OAuth, you can authenticate a user at an external server and get access to their profile info. However, you aren't sharing a session.

A user logs in to website foo.com using Google OAuth. Next he visits website bar.org which also uses Google OAuth. Regardless of that, he is still required to press on the 'login' button on bar.org.

With Jasny SSO both websites use the same session. So when the user visits bar.org, he's automatically logged in. When he logs out (on either of the sites), he's logged out for both.

Installation

Install this library through composer

composer require jasny/sso

Demo

There is a demo server and two demo brokers as example. One with normal redirects and one using JSONP / AJAX.

To proof it's working you should setup the server and two or more brokers, each on their own machine and their own (sub)domain. However, you can also run both server and brokers on your own machine, simply to test it out.

On *nix (Linux / Unix / OSX) run:

php -S localhost:8000 -t demo/server/
export SSO_SERVER=http://localhost:8000/attach.php SSO_BROKER_ID=Alice SSO_BROKER_SECRET=8iwzik1bwd; php -S localhost:8001 -t demo/broker/
export SSO_SERVER=http://localhost:8000/attach.php SSO_BROKER_ID=Greg SSO_BROKER_SECRET=7pypoox2pc; php -S localhost:8002 -t demo/broker/
export SSO_SERVER=http://localhost:8000/attach.php SSO_BROKER_ID=Julius SSO_BROKER_SECRET=ceda63kmhp; php -S localhost:8003 -t demo/ajax-broker/

Now open some tabs and visit

username password
jackie jackie123
john john123

Note that after logging in, you need to refresh on the other brokers to see the effect.

Usage

Server

The Server class takes a callback as first constructor argument. This callback should lookup the secret for a broker based on the id.

The second argument must be a PSR-16 compatible cache object. It's used to store the link between broker token and client session.

use Jasny\SSO\Server\Server;

$brokers = [
    'foo' => ['secret' => '8OyRi6Ix1x', 'domains' => ['example.com']],
    // ...
];

$server = new Server(
    fn($id) => $brokers[$id] ?? null, // Unique secret and allowed domains for each broker.
    new Cache()                       // Any PSR-16 compatible cache
);

In this example the brokers are simply configured as array. But typically you want to fetch the broker info from a DB.

Attach

A client needs attach the broker token to the session id by doing an HTTP request to the server. This request can be handled by calling attach().

The attach() method returns a verification code. This code must be returned to the broker, as it's needed to calculate the checksum.

$verificationCode = $server->attach();

If it's not possible to attach (for instance in case of an incorrect checksum), an Exception is thrown.

Handle broker API request

After the client session is attached to the broker token, the broker is able to send API requests on behalf of the client. Calling the startBrokerSession() method with start the session of the client based on the bearer token. This means that these request the server can access the session information of the client through $_SESSION.

$server->startBrokerSession();

The broker could use this to login, logout, get user information, etc. The API for handling such requests is outside the scope of the project. However since the broker uses normal sessions, any existing the authentication can be used.

If you're lookup for an authentication library, consider using Jasny Auth.

PSR-7

By default, the library works with superglobals like $_GET and $_SERVER. Alternatively it can use a PSR-7 server request. This can be passed to attach() and startBrokerSession() as argument.

$verificationCode = $server->attach($serverRequest);

Session interface

By default, the library uses the superglobal $_SESSION and the php_session_*() functions. It does this through the GlobalSession object, which implements SessionInterface.

For projects that use alternative sessions, it's possible to create a wrapper that implements SessionInterface.

use Jasny\SSO\Server\SessionInterface;

class CustomerSessionHandler implements SessionInterface
{
    // ...
}

The withSession() methods creates a copy of the Server object with the custom session interface.

$server = (new Server($callback, $cache))
    ->withSession(new CustomerSessionHandler());

The withSession() method can also be used with a mock object for testing.

Logging

Enable logging for debugging and catching issues.

$server = (new Server($callback, $cache))
    ->withLogging(new Logger());

Any PSR-3 compatible logger can be used, like Monolog or Loggy. The context may contain the broker id, token, and session id.

Broker

When creating a Broker instance, you need to pass the server url, broker id and broker secret. The broker id and secret needs to match the secret registered at the server.

CAVEAT: The broker id MUST be alphanumeric.

Attach

Before the broker can do API requests on the client's behalve, the client needs to attach the broker token to the client session. For this, the client must do an HTTP request to the SSO Server.

The getAttachUrl() method will generate a broker token for the client and use it to create an attach URL. The method takes an array of query parameters as single argument.

There are several methods in making the client do an HTTP request. The broker can redirect the client or do a request via the browser using AJAX or loading an image.

$attachUrl"; exit(); }">
use Jasny\SSO\Broker\Broker;

// Configure the broker.
$broker = new Broker(
    getenv('SSO_SERVER'),
    getenv('SSO_BROKER_ID'),
    getenv('SSO_BROKER_SECRET')
);

// Attach through redirect if the client isn't attached yet.
if (!$broker->isAttached()) {
    $returnUrl = (!empty($_SERVER['HTTPS']) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    $attachUrl = $broker->getAttachUrl(['return_url' => $returnUrl]);

    header("Location: $attachUrl", true, 303);
    echo "You're redirected to $attachUrl";
    exit();
}

Verify

Upon verification the SSO Server will return a verification code (as query parameter or in the JSON response). The code is used to calculate the checksum. The verification code prevents session hijacking using an attach link.

if (isset($_GET['sso_verify'])) {
    $broker->verify($_GET['sso_verify']);
}

API requests

Once attached, the broker is able to do API requests on behalf of the client. This can be done by

  • using the broker request() method, or by
  • using any HTTP client like Guzzle

Broker request

// Post to modify the user info
$broker->request('POST', '/login', $credentials);

// Get user info
$user = $broker->request('GET', '/user');

The request() method uses Curl to send HTTP requests, adding the bearer token for authentication. It expects a JSON response and will automatically decode it.

HTTP library (Guzzle)

To use a library like Guzzle or Httplug, get the bearer token using getBearerToken() and set the Authorization header

$guzzle = new GuzzleHttp\Client(['base_uri' => 'https://sso-server.example.com']);

$res = $guzzle->request('GET', '/user', [
    'headers' => [
        'Authorization' => 'Bearer ' . $broker->getBearerToken()
    ]
]);

Client state

By default, the Broker uses the cookies ($_COOKIE and setcookie()) via the Cookies class to persist the client's SSO token.

Cookie

Instantiate a new Cookies object with custom parameters to modify things like cookie TTL, domain and https only.

use Jasny\SSO\Broker\{Broker,Cookies};

$broker = (new Broker(getenv('SSO_SERVER'), getenv('SSO_BROKER_ID'), getenv('SSO_BROKER_SECRET')))
    ->withTokenIn(new Cookies(7200, '/myapp', 'example.com', true));

(The cookie can never be accessed by the browser.)

Session

Alternative, you can store the SSO token in a PHP session for the broker by using SessionState.

use Jasny\SSO\Broker\{Broker,Session};

session_start();

$broker = (new Broker(getenv('SSO_SERVER'), getenv('SSO_BROKER_ID'), getenv('SSO_BROKER_SECRET')))
    ->withTokenIn(new Session());

Custom

The method accepts any object that implements ArrayAccess, allowing you to create a custom handler if needed.

class CustomStateHandler implements \ArrayAccess
{
    // ...
}

This can also be used with a mock object for testing.

Comments
  • Different Broker is how to get the same session_id?

    Different Broker is how to get the same session_id?

    I read the code several times, but did not understand how different Broker got the same session_id, and would be very much appreciated if I could tell the logic and flow of this program

    opened by tangzhangming 11
  • everyday log out

    everyday log out

    Hi, I started using this SSO and almost every things seem fine. The only thing I notice every day when I visit my site I need to log in (logged out from all sites). Is there any session inactive duration that is killing/expiring the session so that every day I need to do log in? I have set cookies lifetime for 1 week.

    opened by pramodwerea 10
  • unable to auto login

    unable to auto login

    i logged in on s1 then i went to s2 still the login form is show.

    i created a demo, no changes has been made in the source code except for the server url.and the broker for each domain. server url is http://85.214.200.88/sso/.

    s1: http://arnelqlabarda.com/testing/sso/ s2: http://85.214.200.88/sso/login/

    i checked the server tmp dir.. this is what i have.

    -rw-r--r-- 1 www-data www-data   26 Feb  8 09:52 SSO-BINCK-f1f8f90da0380e4cc44a781b67136664-b1e1f0927c2dc7fc9fd1586a2fb47d3d
    -rw-r--r-- 1 www-data www-data   26 Feb  8 09:52 SSO-LYNX-a54cd54a56a688309cb301ff9739d978-5f14e5d9a1e3f8e57d1f890921349c64
    -rw-r--r-- 1 www-data www-data   26 Feb  8 09:52 SSO-UZZA-28f7a678f27c5bd01d030d2d6374986b-0744949136594cfe0aab565d9b620591
    
    opened by aqlx86 10
  • Expected application/json response, got text/html error

    Expected application/json response, got text/html error

    Hello,

    When I try the examples on my virtual machine I have no problem and that's works fine but when I put it into a web server, I have this error every time Expected application/json response, got text/html

    Do you know why I have this error ?

    Thank's a lot,

    PetitBX

    opened by petitbx 7
  • this really needs a simple instalation guide.

    this really needs a simple instalation guide.

    I would really like to use this! But I need a few words on how to install and test it all. the demo's are offline, so I really don't know where to start now

    opened by flyon 7
  • Session Lost on Second Broker

    Session Lost on Second Broker

    Hi, I tried to implement "Single Sign-On" within our applications. It works fine in localhost but when we tried to deploy this on web then it work with in single broker. It mean when we jump on second broker the session lost and login box start displaying instead of displaying index.php of second broker.

    localhost/sso-live/broker1 localhost/sso-live/broker2

    foo.com/sso-live/broker1 foo.com/sso-live/broker2

    Please help me out to resolve this.

    opened by dmiepub 7
  • Any Help implementing it with Laravel 4 or 5

    Any Help implementing it with Laravel 4 or 5

    Hi,

    First of the congrats and thanks for this wonderful library

    Please do favour and help me implementing it with laravel.

    I think only big problem i could get is with merging the vendor folder because what you used is already used in Laravel.

    Kindly Help. Thanks!

    opened by corientdev 6
  • Demo not working in Chrome 88.0.4324.146

    Demo not working in Chrome 88.0.4324.146

    First off, thanks for this project! I'm currently evaluating if I can use it on a project of mine. The SSO works in Firefox but doesn't work in Chrome. Not sure why that is as the tricky parts are in the backend (PHP) which should be for all browsers the same.

    The login in general works in Chrome, but it only logs you in to the current domain.

    My setup:

    • macOS Big Sur (11.2)
    • Tested in Chrome 88.0.4324.146 (not working)
    • Tested in Firefox 85.0.1 (working)
    • No web extensions installed, no error messages in the frontend or backend which would explain why it's not working.

    How to reproduce:

    • git clone [email protected]:jasny/sso.git
    • Start servers and brokers as described in the README.md file
    • Login to the brokers with one of the defined users

    Can you reproduce this bug? Any hints on how to fix it? Thanks!

    opened by dpacassi 4
  • Unknow command

    Unknow command

    This error occurs after you fill the fields: email and password and hit the login button. The server response with:

    Exception
    Unknown command
    --
    in Client1Broker.php (line 60)
    at Client1Broker->request('POST', 'login-user', array('error' => 'Unknown command'))in Broker.php (line 291)
    at Broker->__call('loginUser', array('[email protected]', 'jackie123'))in LoginController.php (line 47)
    

    Anyone know what can be the problem? Thanks!

    opened by andersonn-roberto 4
  • One Login Form (Server)

    One Login Form (Server)

    I have implement your code to one form Login on server. But, I have stuck.

    Broker > attach to server Broker > Server::GetUserInfo (Curl) > False > Server::Login Form (Redirect) > Broker (Redirect) Broker > Server::GetUserInfo (Curl) > No Session (This fail)

    Can I use your code for that rule? I know the session is not shared. But, how can I get it? Any Idea?

    opened by danuri 4
  • The Session ID of the Broker and ajax-Broker is different

    The Session ID of the Broker and ajax-Broker is different

    broker: a.com ajax-broker: b.com

    When I set above,I find their session id is different!when I Have logged in a.com, b.com can not gets the logged in status。

    you can help me figure out why?

    opened by xiaojunlu 3
  • error ArrayAccess

    error ArrayAccess

    During inheritance of ArrayAccess: Uncaught ErrorException: Return type of Jasny\SSO\Broker\Cookies::offsetExists($name) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/sso-umsby/sso-pakar/vendor/jasny/sso/src/Broker/Cookies.php:79

    opened by asnanmtakim 1
  • Multiple redirects, results in wrong referer validation

    Multiple redirects, results in wrong referer validation

    I have a setup with 2 brokers and a server.

    When I click in the browser from broker1 to broker2. And then PHP (from broker2) redirects to the SSO-server. My Referer header in the SSO-server is then "broker1" and not the expected "broker2".

    This triggers the BrokerException("Domain of $type is not allowed", 400); on the SSO-server Because the SSO server detects the wrong broker.

    After some googling, I found this, which confirms my problems: https://stackoverflow.com/questions/2158283/will-a-302-redirect-maintain-the-referer-string It seems somewhat browser dependant, but most browsers keep the first referer header.

    opened by rauwebieten 3
  • Is it possible to generate a token using jasny sso from an external non php project?

    Is it possible to generate a token using jasny sso from an external non php project?

    Been reading through the documentation and I'm unable to figure out if it is possible for a non php application to hook back into the jasny sso.

    Use Case: SSO implemented on a main project built in PHP and Third party application (for example java project) using the main project's sso server to do the following

    1. Login
    2. Generate token
    3. Validate session which was generated on main project site.

    Is this new functionality that would have to be developed on top of the jasny codebase or is the reason why this functionality does not exist already??

    @jasny

    opened by efernandes-dev-ops 5
Releases(v0.4.0)
  • v0.4.0(Oct 5, 2020)

    PHP 7.3+. PSR-7 support. Rewritten as a proper includable library. Moved authentication out of the library. Return verification code to prevent session hijacking. Alternative to using sessions on server. Alternative to using cookies on server.

    Source code(tar.gz)
    Source code(zip)
Owner
Arnold Daniels
Web and blockchain developer at @ltonetwork
Arnold Daniels
Open source social sign on PHP Library. HybridAuth goal is to act as an abstract api between your application and various social apis and identities providers such as Facebook, Twitter and Google.

Hybridauth 3.7.1 Hybridauth enables developers to easily build social applications and tools to engage websites visitors and customers on a social lev

hybridauth 3.3k Dec 23, 2022
:atom: Social (OAuth1\OAuth2\OpenID\OpenIDConnect) sign with PHP :shipit:

SocialConnect Auth Getting Started :: Documentation :: Demo Open source social sign on PHP. Connect your application(s) with social network(s). Code e

SocialConnect 518 Dec 28, 2022
:atom: Social (OAuth1\OAuth2\OpenID\OpenIDConnect) sign with PHP :shipit:

SocialConnect Auth Getting Started :: Documentation :: Demo Open source social sign on PHP. Connect your application(s) with social network(s). Code e

SocialConnect 458 Apr 1, 2021
Social (OAuth1\OAuth2\OpenID\OpenIDConnect) sign with PHP

Open source social sign on PHP. Connect your application(s) with social network(s).

SocialConnect 517 Dec 11, 2022
Sign into your Flarum forum with your Amazon account

Log In With Amazon A Flarum extension. Log in to your Flarum forum with Amazon. An addon for FoF OAuth Installation Install with composer: composer re

Ian Morland 0 May 4, 2022
Single file PHP that can serve as a JWT based authentication provider to the PHP-CRUD-API project

Single file PHP that can serve as a JWT based authentication provider to the PHP-CRUD-API project

Maurits van der Schee 163 Dec 18, 2022
StartZ oauth2-etsy compatible League of PHP OAuth2

Etsy Provider for OAuth 2.0 Client This package provides Etsy OAuth 2.0 support for the PHP League's OAuth 2.0 Client. Requirements The following vers

StartZ 2 Nov 10, 2022
Instantly login as user via a single button tap on dev environments.

Getting tired of always entering login details in local dev environments? This package adds a button to instantly login a user! Installation You can i

Quinten Buis 3 Feb 18, 2022
A One Time Password Authentication package, compatible with Google Authenticator.

Google2FA Google Two-Factor Authentication for PHP Google2FA is a PHP implementation of the Google Two-Factor Authentication Module, supporting the HM

Antonio Carlos Ribeiro 1.6k Dec 30, 2022
php database agnostic authentication library for php developers

Whoo Whoo is a database agnostic authentication library to manage authentication operation easily. Whoo provides you a layer to access and manage user

Yunus Emre Bulut 9 Jan 15, 2022
OAuth 1/2 Provider implementations for chillerlan/php-oauth-core. PHP 7.4+

chillerlan/php-oauth-providers Documentation See the wiki for advanced documentation. Requirements PHP 7.4+ a PSR-18 compatible HTTP client library of

chillerlan 4 Dec 2, 2022
A Native PHP MVC With Auth. If you will build your own PHP project in MVC with router and Auth, you can clone this ready to use MVC pattern repo.

If you will build your own PHP project in MVC with router and Auth, you can clone this ready to use MVC pattern repo. Auth system is implemented. Works with bootstrap 5. Composer with autoload are implemented too for future composer require.

null 2 Jun 6, 2022
A spec compliant, secure by default PHP OAuth 2.0 Server

PHP OAuth 2.0 Server league/oauth2-server is a standards compliant implementation of an OAuth 2.0 authorization server written in PHP which makes work

The League of Extraordinary Packages 6.2k Jan 4, 2023
Multi-provider authentication framework for PHP

Opauth is a multi-provider authentication framework for PHP, inspired by OmniAuth for Ruby. Opauth enables PHP applications to do user authentication

Opauth – PHP Auth Framework 1.7k Jan 1, 2023
PHP 5.3+ oAuth 1/2 Client Library

PHPoAuthLib NOTE: I'm looking for someone who could help to maintain this package alongside me, just because I don't have a ton of time to devote to i

David Desberg 1.1k Dec 27, 2022
A flexible, driver based Acl package for PHP 5.4+

Lock - Acl for PHP 5.4+ I'm sad to say that Lock is currently not maintained. I won't be able to offer support or accept new contributions for the cur

Beatswitch 892 Dec 30, 2022
PHP library for Two Factor Authentication (TFA / 2FA)

PHP library for Two Factor Authentication PHP library for two-factor (or multi-factor) authentication using TOTP and QR-codes. Inspired by, based on b

Rob Janssen 896 Dec 30, 2022
documentation for the oauth2-server-php library

OAuth2 Server PHP Documentation This repository hosts the documentation for the oauth2-server-php library. All submissions are welcome! To submit a ch

Brent Shaffer 227 Nov 24, 2022
Hawk — A PHP Implementation

Hawk — A PHP Implementation Hawk is an HTTP authentication scheme using a message authentication code (MAC) algorithm to provide partial HTTP request

dflydev 68 Mar 16, 2022