Single Sign-On for PHP (Ajax compatible)

Last update: May 19, 2022

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.

GitHub

https://github.com/jasny/sso
Comments
  • 1. 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

    Reviewed by tangzhangming at 2017-12-12 23:14
  • 2. 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.

    Reviewed by pramodwerea at 2017-05-18 07:53
  • 3. 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
    
    Reviewed by aqlx86 at 2013-02-08 04:52
  • 4. 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

    Reviewed by petitbx at 2016-09-08 13:13
  • 5. 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

    Reviewed by flyon at 2014-06-02 08:37
  • 6. 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.

    Reviewed by dmiepub at 2014-02-12 10:37
  • 7. 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!

    Reviewed by corientdev at 2016-08-18 15:20
  • 8. 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!

    Reviewed by dpacassi at 2021-02-09 10:00
  • 9. 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!

    Reviewed by andersonn-roberto at 2017-10-27 19:21
  • 10. 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?

    Reviewed by danuri at 2017-04-10 02:25
  • 11. Call to undefined function Jasny\SSO\getallheaders()

    Hello! I'm trying to implement SSO in my projects, but it doesn't work because I'm using nginx and php-fpm therefore getallheaders function is not available. The problem in getBrokerSessionID method. Can you add a fix for it?

    Reviewed by MiragePresent at 2017-11-13 16:14
  • 12. 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.

    Reviewed by rauwebieten at 2021-11-22 11:19
  • 13. 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

    Reviewed by efernandes-dev-ops at 2018-03-26 09:33
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

May 24, 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

May 21, 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

Apr 1, 2021
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

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

May 3, 2022
A One Time Password Authentication package, compatible with Google Authenticator.
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

May 25, 2022
Instantly login as user via a single button tap on dev environments.
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

Feb 18, 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

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

Feb 12, 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

May 24, 2022
Multi-provider authentication framework for PHP
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

May 1, 2022
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

Apr 9, 2022
A flexible, driver based Acl package for PHP 5.4+
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

Mar 10, 2022
PHP library for Two Factor Authentication (TFA / 2FA)
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

May 17, 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

Mar 22, 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

Mar 16, 2022
The first PHP Library to support OAuth for Twitter's REST API.

THIS IS AN MODIFIED VERSION OF ABRAHAMS TWITTER OAUTH CLASS The directories are structured and the class uses PHP5.3 namespaces. Api.php has a new

Feb 11, 2021
PHP library to verify and validate Apple IdentityToken and authenticate a user with Apple ID.

Sign-in with Apple SDK Installation Recommended and easiest way to installing library is through Composer. composer require azimolabs/apple-sign-in-ph

Apr 18, 2022
PHP package built for Laravel 5.* to easily handle a user email verification and validate the email

jrean/laravel-user-verification is a PHP package built for Laravel 5.* & 6.* & 7.* & 8.* to easily handle a user verification and validate the e-mail.

May 17, 2022