Notice
The examples and use cases described here are intended to show the different ways SURF Research Access Management can be used and connected to application. These examples and use cases are not always validated by SURF.
Introduction
This guide will integrate SRAM with PHP using OpenID Connect.
To achieve this, we create a basic PHP web site and add SRAM connectivity to it. There are many libraries that help you with setting up OIDC in PHP. We will first use a very simple and easy to use OpenID Connect package and create a connection with that to sign in a user and retrieve user information.
Prerequisites
- Visual Studio Code (VSCode, or the editor of your preference). We prefer VSCode because it has an built-in web server that can run PHP. Feel free to use any web server, for example XAMP, that you prefer.
- An account and collaboration on SRAM.
- A SRAM application (application/platform) registered with your collaboration. You can request a application after you have set-up your collaboration at SURF via this form.
- Client ID (APP-ID) and Client Secret from SRAM your application registration. (you need the client secret if you use the implicit flow instead of PKCE, more later in this article)
- Callback URL registered in your SRAM application.
- Knowledge of PHP and an installation on your machine.
Setting up SRAM
Before diving into the integration process, ensure you have properly set up SRAM:
- Register with SRAM: If you haven’t already, create an account on SRAM. This account provides you with the necessary credentials and management tools.
- Register your application: After creating an account, register your application (application/platform) with SRAM. During this process, specify callback URLs, desired scopes, and other configurations.
- Configure callback URL with SRAM: Once you have decided on a callback URL (typically https://yourdomain.com/oidc_callback), you need to submit it to SRAM, often via a form in the SRAM dashboard or portal. This ensures that SRAM knows where to redirect users after they have been authenticated. It's always a good idea to include a localhost URL in there for testing the solution locally, so we have registered https://localhost:5000/oidc_callback for development purposes.
With the application registered, we can use the provided credentials (client ID and client secret) and endpoint details to prepare for your application's authentication flow with SRAM.
Important note: the code in this article often follows the happy flow so we can emphasis on the working. You should not use it as is in your code. You have to make your code robust, like responsive to missing variables, servers who do not respond, expiring tokens.
Step-by-step Implementation:
We start by creating a very minimal web-app using PHP. For OpenId Connect we will use a very simple but powerful library called Jumbojett\OpenIDConnectClient (you can find it at jumbojett/OpenID-Connect-PHP: Minimalist OpenID Connect client (github.com)).
Depending on the authorization flow you are using you need to change some parts. If you use the (most secure) PKCE flow you do not need the client secret. If you use the implicit flow you do need it. The code below is for the PKCE flow, the amendments for the implicit flow are added to the code as remarks.
- Create php file for the root of the application
- Create php as the homepage.
- Create php. This fille will handle the signing in, signing out and the callback. We will use a script variable to tell this php file when we request a sign out.
Signing in and handling the callback can be handled by the same code, since Jumbojett\OpenIDConnectClient can handle it with the same call. - We will also create a config.json file that will contain the requires information for SRAM.
When we sign in we will add the relevant user information to session variables. Within home.php we then can check if we those sessions variables exist and show the values.
home.php
In the editor create a file home.php
and add code for the root of the website.
<?php // home.php $title = "Home Page"; session_start(); if (isset($_SESSION['user_info'])) { $userInfo = $_SESSION['user_info']; } ?> <!DOCTYPE html> <html> <head> <title><?php echo $title; ?></title> </head> <body> <nav> <ul> <li><a href="index.php">Home</a></li> <?php if (isset($userInfo)) : ?> <li><a href="auth.php?signout">Sign out</a></li> <?php else : ?> <li><a href="auth.php">Sign in</a></li> <?php endif; ?> </ul> </nav> <div class="container"> <h1>Welcome <?php echo $userInfo['name'] ?></h1> <p>This is a basic home page created with PHP.</p> </div> </body> </html>
The code in home.php is pretty straightforward. At the start it initializes the use of sessions and it checks if there is an session variable with the name user_info. If so, it assigns it to variable $userinfo.
Then it builds up the homepage and it shows based on the existence of $userinfo a sign-in or a sign-out link.
Note that we have added in one of the links ‘signout’ as a variable to the auth.php page. In that page we will respond to that.
The root file
index.phpindex.php
will be executed when we browse the website. Also when SRAM does the callback this file is started, so we need to test here if we have a regular call (go to home page) or have the callback. In case of the callback we can go back to auth.php since since Jumbojett\OpenIDConnectClient can handle it with the same call authenticate();
<?php // index.php $requestUri = $_SERVER['REQUEST_URI']; $is_callback = str_contains($requestUri, '/oidc_callback'); if ($is_callback) { include('auth.php'); } else { include('home.php'); } ?>
The code in this file is solely to decide whether home.php or auth.php should be called based on the calling url. If that one contains /oidc_callback
we need to go back to auth.php else to home.php.
config.json
So we have everything in place except the real handling of the connection to SRAM. Let’s first create a json file that will contain the required information for the OpenId client. This file will be stored next to the auth.php file, which we will create next.
// config.json { "client_id" : "[YOUR CLIENT ID]", "client_secret" : "[YOUR CLIENT SECRET]", // only needed with auth code flow "redirect_uri" : "http://localhost:5000/oidc_callback", "authority" : "https://proxy.sram.surf.nl", "scopes":["openid", "email", "profile"] }
Jumbojett\OpenIDConnectClient
uses OpenId well known configuration, but you do not need to specify the url to that location. It will use the authority to find it and read the relevant information from it.
Note that you do not need to use a client secret when you use PKCE.
The scopes determine the variables we request from SRAM. Openid, email and profile are most used ones.
<?php // auth.php // load the required libraries and define the use of the OpenIDConnectClient require 'vendor/autoload.php'; use Jumbojett\OpenIDConnectClient; session_start(); // reading the config file. $str = file_get_contents("config.json"); $cfg = json_decode($str, false); // creating the OpenIDConnect client $oidc = new OpenIDConnectClient( $cfg->authority, $cfg->client_id, Null // if you use implicit flow you need to inject here the client secret using // $cfg->client_secret instead of null ); $oidc->setRedirectURL($cfg->redirect_uri); //start signout procedure if ‘signout’ is added to the querystring if(isset($_GET['signout'])) { SignOut(); } else { SignIn(); } function SignOut() { global $oidc,$cfg; if (isset($_SESSION['user_info'])) { $_SESSION['user_info'] = null; } header('Location: index.php'); } function SignIn() { global $oidc, $cfg; $oidc->setCodeChallengeMethod('S256'); $oidc->addScope($cfg->scopes); try { $oidc->authenticate(); $userInfo = $oidc->requestUserInfo(); $_SESSION['user_info'] = [ 'sub' => $userInfo->sub, 'name' => $userInfo->name, 'email' => $userInfo->email ]; header('Location: index.php'); } catch (Exception $e) { echo 'Error: ' . $e->getMessage(); } } ?>
The start of the code initializes the possibility to use sessions variables and reads the config,json file into a variable $cfg.
Then we set up the OpenIdConnect client and inject the information from the configuration.
Please realize that this code is executed in the all cases, regardingless if we are in a sign-in, callback or sign-out. In the next lines we check if ‘signout’ is added to the script variables (auth.php?signout) and now we decide to go to sign out or sign in.
Sign in procedure
In the sign in function we use the defined variables in the top of the file, set the code challenge method and add the scopes from the configuration. We do not have to calculate a code challenge, OpenIDConnectClient handles this for us.
The call authenticate()will sign in the user if the user is not signed in yet. If we sign in, the code stops here! We are redirected to SRAM, we sign in and then the callback happens.
The callback
When the callback is triggered from SRAM we will be send via index.php back in auth.php, start the signin function again and now the authenticate() function will just get (behind the scenes) the required authentication tokens for subsequent calls.
The code will continue to call requestUserInfo(). Under the hood the OpenIdConnect client will use the authentication token and retrieve the user info within the requested scopes. The returned data is mapped into a session variable. If you have added SRAM specific scopes you can map the variables from these scopes here. See Attributes in SRAM - SURF User Knowledge Base - SURF User Knowledge Base for available attributes and scopes.
Directly after we have set the session variable we redirect the code back to index.php. We can also directly go to home.php, but it might be a good idea to have all routing defined in once place.
Sign out procedure
In the sign out procedure (called when ‘signout’ is added to the script variables), we simply remove the user info from the session variables and route back to index.php.
Jumbojett\OpenIDConnectClient
has a SignOut(token, redirect) function to sign out the session on the OpenID server, but this will only work if the well know configuration contains end_session_endpoint, which is not the case with SRAM.
And we are there! You can log in using SRAM, get user information and log out. The Jumbojett\OpenIDConnectClient
is very simple and easy to use library that handles behind the scenes steps that are often required in OpenIDConnect, such as code challenges.
Conclusion
By following the above steps, you have successfully set up OIDC authentication in a PHP web application using Visual Studio Code.