accredifysg/singpass-login

A Laravel package for integrating SingPass Login

v1.2.0 2025-04-29 08:32 UTC

README

Coverage

PHP Laravel Package for SingPass Login

Official SingPass Login Docs

Installation

You can install the package via composer:

composer require accredifysg/singpass-login

Add the following variables to your .env file.

# SingPass variables
SINGPASS_CLIENT_ID=
SINGPASS_REDIRECT_URI=
SINGPASS_DOMAIN=
SINGPASS_DISCOVERY_ENDPOINT=
SINGPASS_SIGNING_KID=
SINGPASS_JWKS=
SINGPASS_PRIVATE_JWKS=

# Default Routes
SINGPASS_USE_DEFAULT_ROUTES=true
SINGPASS_JWKS_URL=/sp/jwks
SINGPASS_AUTHENTICATION_URL=/sp/login
SINGPASS_CALLBACK_URL=/sp/callback

# Default Listener
SINGPASS_USE_DEFAULT_LISTENER=true

Publish the config file

php artisan vendor:publish --provider="Accredifysg\SingPassLogin\SingPassLoginServiceProvider" --tag="config"

Optionally, you can publish the listener that will listen to the SingPassLoginEvent and log the user in

php artisan vendor:publish --provider="Accredifysg\SingPassLogin\SingPassLoginServiceProvider" --tag="listener"

Usage and Customisations

Controllers and Routes

There are three default controllers that handle the login process

GetJwksEndpointController exposes your application's JWKS endpoint to be registered with SingPass. The default route for this controller is /sp/jwks

GetAuthenticationEndpointController provides the authentication endpoint to redirect the client's browser to. The default route for this controller is /sp/login

PostSingPassCallbackController handles the callback from SingPass, and kick-starts the login process. The default route for this controller is /sp/callback

If you prefer to set your own routes you can set SINGPASS_USE_DEFAULT_ROUTES to false, then edit SINGPASS_JWKS_URL, SINGPASS_CALLBACK_URL, and SINGPASS_AUTHENTICATION_URL in your .env file and map your own routes.

If you prefer to write your own controllers you can define them in the config file singpass-login.php as get_jwks_endpoint_controller, post_singpass_callback_controller and get_authentication_endpoint_controller

Listener

If you published the default listener, you should edit it and map your user retrieval via NRIC accordingly.

public function handle(SingPassSuccessfulLoginEvent $event): RedirectResponse
    {
        $singPassUser = $event->getSingPassUser();
        $nric = $singPassUser->getNric();

        $user = User::where('nric', '=', $nric)->first(); // Map to your own model that stores the users' NRIC or UUID

        if (! $user) {
            throw new SingPassLoginException;
        }

        Auth::login($user);
    }

If you prefer to write your own, you can set SINGPASS_USE_DEFAULT_LISTENER to false in your .env and replace listener_class in the config file singpass-login.php

Exceptions

<?php
use Accredifysg\SingPassLogin\Exceptions\JweDecryptionFailedException;
use Accredifysg\SingPassLogin\Exceptions\JwksInvalidException;
use Accredifysg\SingPassLogin\Exceptions\JwtDecodeFailedException;
use Accredifysg\SingPassLogin\Exceptions\JwtPayloadException;
use Accredifysg\SingPassLogin\Exceptions\OpenIdDiscoveryException;
use Accredifysg\SingPassLogin\Exceptions\SingPassJwksException;
use Accredifysg\SingPassLogin\Exceptions\SingPassTokenException;
use Accredifysg\SingPassLogin\Exceptions\SingPassLoginException;