devlin/myinfo-singpass-laravel

PHP package for Singpass/Myinfo v5 OIDC FAPI 2.0 integrations.

Maintainers

Package info

github.com/dev-lin2/myinfo_singpass_php

pkg:composer/devlin/myinfo-singpass-laravel

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0

v1.0.1 2026-03-03 02:04 UTC

This package is auto-updated.

Last update: 2026-03-03 09:55:22 UTC


README

PHP package for Singpass / Myinfo v5 integration using OIDC + FAPI 2.0 profile.

Installation

composer require devlin/myinfo-singpass-laravel

Reference

Scope

This package now supports only the modern FAPI 2.0 flow:

  • Pushed Authorization Request (PAR)
  • PKCE (S256)
  • DPoP
  • private_key_jwt client authentication
  • Encrypted + signed id_token validation
  • /userinfo retrieval with Authorization: DPoP <access_token>

Legacy MyInfo /com/v3/* flow is removed.

Required Environment Variables

MYINFO_CLIENT_ID=...
MYINFO_REDIRECT_URI=http://localhost:8080/myinfo/callback

Recommended Environment Variables

MYINFO_ISSUER_URL=https://stg-id.singpass.gov.sg/fapi
MYINFO_SCOPES=openid uinfin name
MYINFO_TIMEOUT_MS=10000

Generating JWK Key Files

This package requires JWK key files for signing and encryption. If you don't have these yet, you can generate them using jwk-cli-tool — an interactive CLI for generating PEM and JWK files.

npx jwk-cli-tool

The tool will guide you through:

  1. Generate PEM Key Pairs — choose your algorithm (ES256, ES384, ES512, RS256, RS384, RS512) to produce .pem files
  2. Generate JWK JSON Files — convert PEM keys to JWK format, set the key use (sig or enc), and assign a key ID

Run it twice — once for your signing key (sig) and once for your encryption key (enc) — then reference the output files in the env vars below.

Requires Node.js 18+.

Key Configuration (choose one)

Option A: Singpass config JSON (recommended)

MYINFO_OIDC_CONFIG_PATH=./config/singpass-config.json

Expected JSON fields are CLIENT_ID, REDIRECT_URI, ISSUER_URL, and KEYS.

Option B: explicit JWK env values

MYINFO_OIDC_PRIVATE_SIG_JWK_PATH=./myinfo/private_sig.jwk.json
MYINFO_OIDC_PUBLIC_SIG_JWK_PATH=./myinfo/public_sig.jwk.json
MYINFO_OIDC_PRIVATE_ENC_JWK_PATH=./myinfo/private_enc.jwk.json

Optional Reliability Settings

MYINFO_OIDC_RETRY_ATTEMPTS=3
MYINFO_OIDC_RETRY_BACKOFF_MS=250
MYINFO_OIDC_CLIENT_ASSERTION_AUDIENCE=

MYINFO_OIDC_CLIENT_ASSERTION_AUDIENCE is optional. If empty, the package uses OIDC discovery issuer.

Optional Signature Verification Key Override

By default, the package verifies ID token and UserInfo signatures using the issuer discovery jwks_uri.

If you want to pin verification keys locally, set either:

MYINFO_OIDC_VERIFICATION_JWKS_PATH=./myinfo/myinfo_pub.jwk.json

or

MYINFO_OIDC_VERIFICATION_JWKS_JSON={...}

Accepted formats:

  • JWKS object: { "keys": [ ... ] }
  • single JWK object
  • array of JWK objects

Minimal Usage

use Illuminate\Support\Str;
use MyInfo\Laravel\Facades\MyInfo;

// Redirect step
$state = Str::random(32);
$nonce = Str::random(32);
$codeVerifier = rtrim(strtr(base64_encode(random_bytes(64)), '+/', '-_'), '=');

session([
    'myinfo_state_'.$state => [
        'code_verifier' => $codeVerifier,
        'nonce' => $nonce,
    ],
]);

$url = MyInfo::buildAuthorizeUrl([
    'state' => $state,
    'nonce' => $nonce,
    'code_verifier' => $codeVerifier,
]);

return redirect()->away($url);
use MyInfo\Laravel\Facades\MyInfo;

// Callback step
$code = (string) request('code', '');
$state = (string) request('state', '');
$ctx = (array) session('myinfo_state_'.$state, []);
session()->forget('myinfo_state_'.$state);

$token = MyInfo::exchangeToken($code, null, [
    'code_verifier' => (string) ($ctx['code_verifier'] ?? ''),
    'nonce' => (string) ($ctx['nonce'] ?? ''),
]);

// id_token claims are already verified (iss, aud, exp, nonce)
$idTokenClaims = $token->getIdTokenClaims();

// Fetch Myinfo user data from /userinfo
$person = MyInfo::getPerson($token->getValue())->toArray();

Runtime Behavior

  • PAR is always used.
  • DPoP is always used for PAR, token, and userinfo calls.
  • token_type must be DPoP.
  • openid must be present in requested scopes.
  • id_token claims are validated: iss, aud, exp, nonce.

Demo

Look for a quick demo here. https://github.com/dev-lin2/myinfo_singpass_php_demo