• Stars
    star
    1,473
  • Rank 31,917 (Top 0.7 %)
  • Language
    PHP
  • License
    MIT License
  • Created almost 15 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Simple Single Sign-On for PHP

jasny-banner

Single Sign-On for PHP

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.

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 <a href='$attachUrl'>$attachUrl</a>";
    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 Session.

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.

More Repositories

1

bootstrap

The missing components for your favorite front-end framework.
JavaScript
2,683
star
2

jquery.smartbanner

Smart Banner support for iOS 4/5 and Android
JavaScript
649
star
3

auth

Authentication, authorization and access control for Slim and other micro-frameworks
PHP
106
star
4

twig-extensions

A number of useful filters for Twig
PHP
103
star
5

switch-route

Generate a PHP script for faster routing πŸš€
PHP
75
star
6

mysql-revisioning

PHP script to add versioning to MySQL data
PHP
69
star
7

audio

Process audio files using SoX
PHP
47
star
8

php-functions

A set PHP functions that SHOULD have been part of PHP's core libraries.
PHP
43
star
9

persist-sql-query

The best and most complete query builder/parser for MySQL (PHP)
PHP
32
star
10

phpdoc-parser

Extract meta data from DocBlock comments in PHP
PHP
32
star
11

dbvc

Manage database updates using version control
PHP
24
star
12

skeleton-php-ext

Skeleton project for PHP extension (written in C)
PowerShell
24
star
13

developer-access

Private/public key authentication in PHP
PHP
23
star
14

http-message

PSR-7 for new and legacy applications
PHP
22
star
15

http-message-php-ext

PSR-7 implementation as PHP extension (pecl)
PHP
21
star
16

formbuilder

A form builder for HTML5 and Twitter Bootstrap
PHP
20
star
17

config

Configure your application in PHP, with PSR-11 implementation
PHP
20
star
18

iso

PHP library around standarized codes
PHP
19
star
19

oauth-lambda

AWS Lambda function for GitHub OAuth authentication
HTML
17
star
20

invite-code

Library for using invitation codes (PHP)
PHP
16
star
21

persist-core

Service based DB abstraction layer for PHP
PHP
15
star
22

base58-php-ext

PHP extension for base58 encoding and decoding using the Bitcoin alphabet
PowerShell
15
star
23

dotkey

Access objects and arrays through dot notation
PHP
14
star
24

improved-php-iterable

Functions working with arrays, Iterators and other Traversable objects (PHP)
PHP
14
star
25

db-mysql

A simple class for using MySQL
PHP
13
star
26

lib-phpdebug-js

XDebug (PHP Debugger) client written in JavaScript
JavaScript
11
star
27

http-signature

PHP library for HTTP Signature IETF draft standard RFC
PHP
9
star
28

typecast

Strict type casting for PHP
PHP
7
star
29

event-loop

A simple event loop implementation for PHP
PHP
7
star
30

error-handler

Error handler with PSR-7 support
PHP
6
star
31

mvc

The basics for an MVC application
PHP
5
star
32

jasny-symfony

No longer maintained
PHP
5
star
33

db-mongo

Service based DB abstraction layer for PHP (MongoDB)
PHP
5
star
34

php-code-quality

Coding standard and quality assurance checks (PHP)
5
star
35

visiting-hours

Let your guests select visiting hours
JavaScript
4
star
36

improved-php-function

Library for function handling and functional programming (PHP)
PHP
4
star
37

improved-php-type

Type checking and casting (PHP)
PHP
4
star
38

phpunit-xsdvalidation

XSD schema validation constraint for PHPUnit
PHP
4
star
39

validation-result

A result object for validation (PHP)
PHP
4
star
40

woocommerce-login-redirect-to

Support for `redirect_to` query parameter to specify a redirect page after login via WooCommerce user profile page
PHP
4
star
41

autowire

Autowiring for PSR-11 containers
PHP
3
star
42

Q

Old but sometimes useful code
PHP
3
star
43

immutable

Helper method for immutable objects
PHP
3
star
44

container

PSR-11 compatible container with sub-container and autowiring support (PHP)
PHP
3
star
45

php-consistent-function-names

Userland implementation of PHP RFC: Consistent Function Names
PHP
3
star
46

formbuilder-bootstrap

Bootstrap decorator for Jasny Form builder
PHP
3
star
47

view

An abstraction for using PSR-7 with template engines
PHP
2
star
48

paypal-csv-local-currency

Convert foreign currencies in a PayPal CSV export
HTML
2
star
49

write-protection-php-ext

Write protected objects in PHP (experimental)
PowerShell
2
star
50

varcache

A 500x faster cache implementation for PHP
PHP
2
star
51

substitution.js

JavaScript library to substitute placeholders in a string
JavaScript
2
star
52

envelope-milter

Sendmail/postfix pre-queue filter to check envelope sender against To header
C
2
star
53

db-rest

Database layer for RESTful services
PHP
2
star
54

entity

An entity is an object with a (persistent) data representation.
PHP
2
star
55

event-dispatcher

PSR-14 compatible event dispatcher that's easy to use
PHP
2
star
56

reflection-factory

Abstract factory for PHP Reflection
PHP
2
star
57

phpunit-extension

Additional PHPUnit assertions and helper functions
PHP
2
star
58

meta

Define metadata for classes, properties and functions
PHP
1
star
59

SpotifyThis

Chrome plugin that adds a Spotify Play Button when on an artist page
JavaScript
1
star
60

consolekit-extension

An extension to maximebf/consolekit
PHP
1
star
61

php-rfc-strict-operators

PHP RFC: Strict operators directive
1
star
62

knex-hdb

SAP Hana support for Knex.js
JavaScript
1
star
63

router

A versatile router for PHP
PHP
1
star
64

improved-php-string

Don't look at me. I'm not ready yet!
PHP
1
star
65

session-middleware

PSR-15 session middleware
PHP
1
star
66

reset-php.ini

Set PHP ini configuration that changes runtime behavior to standard values
PHP
1
star
67

persist-orm

ORM/ODM for Jasny Persist
PHP
1
star
68

mongodb-northwind

MongoDB version of Northwind demo database
JavaScript
1
star
69

social

A cool web service API abstraction layer for PHP
PHP
1
star
70

forwarded-middleware

Middleware to handle the Forwarded header for trusted proxies (PHP)
PHP
1
star
71

utf8-php-ext

UTF-8 string functions for PHP
PHP
1
star
72

firewall

A very simple firewall script
Shell
1
star
73

improved-php

Consistent, modern and safe functions (PHP) - meta package
1
star