Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

University of Rwanda — Single Sign-On (SSO) Portal

How it works, how apps connect, and what to expect

This guide explains UR SSO for leaders, stakeholders, and developers building UR apps (Umutungo, AMS, Library, …). It covers what SSO is, what data apps receive, and a step-by-step process to connect a new application.

This repository is the public home for UR SSO documentation and diagrams. App teams use it without needing access to the Inuma codebase.

Platform / IdP operations (issuer keys, cookie domain) are handled by the Inuma SSO administrators — contact them if you need production issuer details.

Quick developer reference: DEVELOPER.md.


Table of Contents

  1. Executive Summary
  2. What Is Single Sign-On?
  3. Benefits & Business Value
  4. What the Staff Experience Looks Like
  5. How It Works
  6. What Data Apps Can Receive
  7. The Login Flow
  8. How to Connect Your App to UR SSO
  9. Security & Logout
  10. Rollout Roadmap
  11. FAQ
  12. Glossary

1. Executive Summary

The UR Single Sign-On (SSO) Portal lets every staff member use one account — their existing Inuma account — to log in to all University of Rwanda digital systems. Instead of remembering a different username and password for each system, staff sign in once and are automatically recognized everywhere.

We already hold accurate staff information and login credentials inside Inuma. SSO turns Inuma into the central identity system ("the front door") for the University, so new and existing applications can rely on it for secure login.

In one sentence: One UR account, one login, every UR system — secure, consistent, and centrally managed.

At a glance

SSO overview — login flow via Inuma OIDC, and how SSO proves who you are while each app decides what you can do.

This is built on OpenID Connect (OIDC) — the same open standard behind "Sign in with Google" — so it is proven, secure, and future-proof.

2. What Is Single Sign-On?

Today, each system tends to have its own separate login. Staff juggle multiple passwords; IT manages multiple user lists; when someone leaves, their access has to be removed from many places.

Single Sign-On solves this. There is one trusted login service (Inuma). Every other system asks Inuma: "is this person who they say they are?" The staff member logs in once, and every connected system trusts that answer.

Think of it like a staff ID badge for the digital world: you show it once at the main entrance, and it opens every door you are authorized to use — instead of a separate key for every room.

3. Benefits & Business Value

For staff

  • One account and one password to remember (or passwordless email-code login).
  • Log in once, move between systems without logging in again.
  • A familiar, branded University of Rwanda Single Sign-On experience.

For the University / management

  • Single source of truth for identity — staff data lives in one place.
  • Faster onboarding: a new app can be connected quickly via the admin portal.
  • Instant offboarding: disable one Inuma account and access to every connected system is revoked for new logins.
  • Consistency: shared identity across UR systems.

For security & compliance

  • Central control and an audit trail of who signed into what and when.
  • Fewer passwords stored across systems = smaller attack surface.
  • Standards-based technology (OpenID Connect / OAuth 2.0).

For cost & scale

  • Reuses staff data and credentials already in Inuma — no separate identity product to license.
  • Ready to connect third-party tools later (e.g. Moodle) because it follows an open standard.

4. What the Staff Experience Looks Like

  1. A staff member opens any UR system (for example, AMS or a Library app).
  2. If they are not logged in, they are taken to the familiar UR Single Sign-On page (Inuma login), which shows something like "Sign in to continue to Library".
  3. They log in with their Inuma email + password (or a one-time email code).
  4. They are sent straight back into the app — already signed in.
  5. When they open another UR system in the same browser session, they are not asked to log in again (silent SSO).
  6. Optionally, a "My Apps" page in Inuma lists connected systems they can open with one click.

Staff do not need to visit Inuma first. They can start from any connected app and click Sign in with UR SSO.

5. How It Works

Inuma is the Identity Provider (IdP). Each other UR application is a client. They speak OpenID Connect (OIDC) using Authorization Code + PKCE — the recommended pattern for web and single-page apps.

Inuma as Identity Provider — UR apps redirect to OIDC at /oidc for sign-in; Inuma issues tokens and reuses login sessions from the database.

Key ideas

  • There is no second password store — login reuses Inuma credentials and session.
  • Apps receive signed tokens, never the password.
  • Admins decide which apps may use SSO and which staff fields each app may receive.
  • SSO answers "who is this person?" Each app still decides "what can they do here?" with its own roles.

6. What Data Apps Can Receive

When an admin onboards an app, they grant scopes. The app only receives the claims allowed by those scopes.

Scope What the app can receive
openid (required) Stable user id (sub)
profile Name, position, function, staff level, unit type, unit, department, school, campus, organisation, institution, employee id, picture
email Email (+ verified)
phone Phone number
ur_roles Coarse role only (e.g. staff / hod) — not Inuma’s fine-grained permissions
ur_acting Whether they are acting, and who/where they are acting for (name, position, unit)
ur_hr Gender, date of birth, degree, qualification, employment date/group (opt-in)
offline_access Refresh tokens (not profile data)

Defaults for new apps: openid profile email ur_roles offline_access
(ur_acting and ur_hr are opt-in.)

Never sent via SSO: password, bank details, RSSB, or other highly sensitive fields.

Example (profile + email + roles + acting)

{
  "sub": "68e4e5ca9b137a806e0d5b5a",
  "name": "Jane Doe",
  "email": "jane@ur.ac.rw",
  "email_verified": true,
  "position": "Asset Manager",
  "function": "Academic Staff",
  "staff_level": "L5",
  "unit_type": "DEPARTMENT",
  "unit": "Computer Science",
  "department": "Computer Science",
  "school": "College of Science",
  "campus": "Nyarugenge",
  "institution": "University of Rwanda",
  "employee_id": 12345,
  "role": "staff",
  "is_acting": true,
  "acting_for": [
    {
      "id": "68e4e5ca9b137a806e0d5b5b",
      "name": "Jean Official",
      "position": "Dean",
      "unit_type": "SCHOOL",
      "unit": "School of ICT"
    }
  ]
}

7. The Login Flow

SSO login flow — staff opens a UR app, signs in via Inuma OIDC, receives tokens (never the password). SSO proves identity; each app decides authorization.

Once the Inuma session exists in that browser, opening another UR app usually needs no second password.

SSO answers "Who are you?" — applications answer "What can you do?"

8. How to Connect Your App to UR SSO

This section is for anyone building a UR application (Umutungo, AMS, Library, HR tools, …). Think of it like connecting "Login with Google" — except the login provider is Inuma / UR SSO.

Connect your app to Inuma OIDC — 7 steps: contact admin, get Client ID, install library, set env vars, add login button, handle callback, use identity.

Use an AI coding agent (Cursor, Claude Code, …)

After the admin gives you a Client ID, paste the ready-made prompt from AGENT_PROMPT.md into Cursor / Claude Code / Copilot Chat. Fill in issuer, Client ID, redirect URI, and scopes — the agent can wire the integration into your app.

8.1 Step 1 — Contact the Inuma SSO admin

Email or message the Inuma / UR SSO administrator and ask them to onboard your app. Send them this information:

What to send Example (Umutungo) Why
App name Umutungo Shown on login / My Apps
App home URL https://umutungo.ur.ac.rw Launcher link
Login callback URL(s) https://umutungo.ur.ac.rw/callback Where Inuma returns after login — must match exactly
Logout return URL(s) https://umutungo.ur.ac.rw Where users land after SSO logout
App type Browser SPA (React) or server app Public + PKCE vs Confidential + secret
Scopes you need Usually openid profile email ur_roles offline_access What staff fields you receive
Local/dev callback (optional) http://localhost:5173/callback So you can test on your machine

Ask for acting/HR data only if you truly need it (ur_acting, ur_hr).

The admin registers the app in Inuma → UR SSO → Onboarding Apps.

8.2 Step 2 — Receive credentials from the admin

The admin will send you back:

You receive Browser SPA (most UR apps) Server app
Client ID Yes (e.g. ur_83d8…) Yes
Client secret No — never put a secret in frontend code Yes — store only on the server
Issuer URL https://inuma.ur.ac.rw/oidc Same
Allowed scopes The list they approved Same
Registered redirect URI Exactly what you asked for Same

Keep the Client ID (and secret, if any) out of public git repos when possible — use environment variables.

8.3 Step 3 — Install the OIDC library

For a typical React / Vite UR app:

npm install oidc-client-ts react-oidc-context

Other stacks:

Stack Suggested library
React SPA oidc-client-ts + react-oidc-context
Vue / plain JS SPA oidc-client-ts
Node / Next server openid-client (confidential client)

A full copy-paste React sample lives in examples/oidc-client-react.

8.4 Step 4 — Put values in your environment

Create (or update) .env in your app:

# Inuma OIDC issuer (do not add a trailing slash after /oidc unless told to)
VITE_SSO_ISSUER=https://inuma.ur.ac.rw/oidc

# From the SSO admin
VITE_SSO_CLIENT_ID=ur_xxxxxxxxxxxxxxxx

Local development example:

VITE_SSO_ISSUER=http://localhost:3000/oidc
VITE_SSO_CLIENT_ID=ur_xxxxxxxxxxxxxxxx

Important: the redirect URI your code builds (see next step) must be exactly one of the URIs the admin registered (including http vs https, port, and path).

8.5 Step 5 — Configure OIDC in the app

Example config (React):

// src/oidcConfig.ts
import { WebStorageStateStore } from 'oidc-client-ts';
import type { AuthProviderProps } from 'react-oidc-context';

export const oidcConfig: AuthProviderProps = {
  authority: import.meta.env.VITE_SSO_ISSUER,
  client_id: import.meta.env.VITE_SSO_CLIENT_ID,
  redirect_uri: `${window.location.origin}/callback`,
  post_logout_redirect_uri: window.location.origin,
  response_type: 'code',
  scope: 'openid profile email ur_roles offline_access',
  userStore: new WebStorageStateStore({ store: window.localStorage }),
  automaticSilentRenew: true,
  onSigninCallback: () => {
    window.history.replaceState({}, document.title, window.location.pathname);
  },
};

Wrap your app with the auth provider (once, at the root):

// src/main.tsx
import { AuthProvider } from 'react-oidc-context';
import { oidcConfig } from './oidcConfig';

<AuthProvider {...oidcConfig}>
  <App />
</AuthProvider>;

Use the same scopes the admin granted. Do not request scopes that were not approved.

8.6 Step 6 — Add “Sign in with UR SSO” on the login page

On your login screen (Umutungo login, AMS login, …), add a button that starts the redirect:

import { useAuth } from 'react-oidc-context';

function LoginPage() {
  const auth = useAuth();

  return (
    <button type="button" onClick={() => void auth.signinRedirect()}>
      Sign in with UR SSO
    </button>
  );
}

What happens when the user clicks it:

  1. Browser goes to Inuma SSO.
  2. User signs in with their existing Inuma account (if not already signed in).
  3. Inuma sends them back to your /callback with a one-time code.
  4. The library exchanges the code for tokens.
  5. Your app is signed in — you never see their password.

8.7 Step 7 — Handle the callback route

Make sure your router serves the app at /callback (same origin as redirect_uri). With react-oidc-context, mounting <App /> (inside AuthProvider) on both / and /callback is enough — the library detects ?code= and finishes login.

After success, read the staff profile:

const auth = useAuth();
const profile = auth.user?.profile;

// Examples of claims (if scopes were granted):
// profile.sub, profile.name, profile.email, profile.position,
// profile.unit_type, profile.unit, profile.role, profile.acting_for

Call your own APIs with:

Authorization: Bearer <access_token>

Your API should validate the token against Inuma’s JWKS ({issuer}/jwks).

8.8 Step 8 — Map identity into your app roles

SSO tells you who the person is. Your app still decides what they can do.

Typical pattern for Umutungo / AMS / any UR product:

  1. After SSO login, read email or sub.
  2. Find or create the user in your database.
  3. Apply your roles (umutungo_admin, asset_manager, …) from your DB.
  4. Optionally use Inuma claims (unit, campus, acting_for, …) as context.

Your roles do not need to match Inuma roles. Inuma permissions are not sent over SSO.

8.9 Step 9 — Test before go-live

Check Expected
Click Sign in with UR SSO Redirects to Inuma login (or silent SSO if already logged in)
After login Returns to your app signed in; profile has name/email
Wrong redirect URI Error redirect_uri mismatch → fix URI with admin
Second UR app in same browser Often no password again (silent SSO)
Sign out Ends session via Inuma when using signoutRedirect()

8.10 Step 10 — Go live & My Apps (optional)

  1. Ask the admin to register the production redirect URI(s).
  2. Put production VITE_SSO_ISSUER + VITE_SSO_CLIENT_ID on the server.
  3. Optionally ask them to enable Show in launcher so the app appears on Inuma My Apps.

8.11 Admin side (short)

Inuma admins manage apps under UR SSO:

Page Path Purpose
Overview /admin/sso Counts and shortcuts
Onboarding Apps /admin/sso/apps Create/edit apps, scopes, logo, activate/deactivate
SSO Logs /admin/sso/logs Audit of SSO events
Client type Use when
Public (PKCE) Browser SPAs — no secret
Confidential Server apps — secret shown once

8.12 Quick checklist for a new UR app (e.g. Umutungo)

  • Contact SSO admin with app name, URLs, type, and scopes
  • Receive Client ID (+ secret only if confidential)
  • Optional: paste AGENT_PROMPT.md into Cursor / Claude Code
  • npm install oidc-client-ts react-oidc-context (or equivalent)
  • Set VITE_SSO_ISSUER and VITE_SSO_CLIENT_ID in .env
  • Configure OIDC (authority, client_id, /callback)
  • Add Sign in with UR SSO button
  • Handle /callback and read profile claims
  • Map sub / email → your app’s users and roles
  • Test login, mismatch errors, and logout
  • Switch env to production issuer + Client ID

9. Security & Logout

Security highlights

  • PKCE required for every client.
  • Exact redirect URI matching (no wildcards).
  • Short-lived access tokens; optional refresh tokens.
  • Rate limiting and audit logging of SSO events.
  • Passwords never leave Inuma; apps only see signed tokens and allowed claims.
  • Deactivating an Inuma account blocks new SSO logins for that person.

Logout

  • An app can send the user to Inuma to end the central session.
  • Apps can also register for back-channel logout so sessions end everywhere when the user signs out.

10. Rollout Roadmap

UR SSO rollout roadmap — stand up, harden production, pilot one app, roll out more apps, enable Single Logout.

  1. Stand up the Inuma SSO provider.
  2. Harden production (stable signing keys, shared cookie domain, HTTPS).
  3. Pilot with one application and real staff.
  4. Onboard remaining UR systems via the admin portal.
  5. Enable full Single Logout where needed.

11. FAQ

Do staff need a new account?

No. They use their existing Inuma account.

Is this like "Login with Google"?

Yes — same idea, university-hosted. Inuma is the identity provider for UR apps. Staff click Sign in with UR SSO, authenticate at Inuma if needed, and return with tokens. The app never sees the password.

Must users log into Inuma before opening another app?

No. They can open any connected app and use Sign in with UR SSO. If they are already signed into Inuma in that browser, the next app often gets silent SSO. My Apps is optional convenience, not a requirement.

How does an app get access to SSO?

Follow §8 How to Connect Your App to UR SSO: contact the admin → get Client ID → install library → set env → add login button → handle callback → map users/roles in your app.

Public vs Confidential — which should we use?

  • Browser / SPA → Public + PKCE (no secret in the frontend).
  • Server backend → Confidential (secret stored only on the server).

What data does Inuma provide to other apps?

Only the claims for scopes the admin granted (see §6). Never the password. Inuma permissions are not shared over SSO.

Why not send every staff field?

Least privilege and privacy. Sensitive fields (bank, RSSB, password) stay out of OIDC. Extra fields use opt-in scopes (ur_hr, ur_acting) or a separate secure API when truly needed. Admins still choose what each app may request.

What if the app has different roles than Inuma?

Expected. SSO proves identity; the app owns authorization. Match the person by email/sub, then use the app’s own roles.

Can admins deactivate an onboarded app?

Yes. Deactivate (or delete) the client under Onboarding Apps. Inactive apps cannot complete new SSO logins.

Is a password shared with other apps?

Never. Apps only receive signed tokens and allowed identity claims.

Does it work for mobile / single-page apps?

Yes — Public client + PKCE, no stored secret in the app.

What if an app is not built by us (e.g. Moodle)?

If it supports standard OpenID Connect, it can be onboarded the same way.

What happens when someone leaves?

Deactivate their Inuma account. New logins to connected systems that rely on Inuma SSO are blocked. Enable back-channel logout so open app sessions can end too.

What if Inuma is down?

Login to connected apps depends on the identity provider, so Inuma should be run for high availability as the university front door.

12. Glossary

  • SSO (Single Sign-On): log in once, access many systems.
  • IdP (Identity Provider): the trusted login service — here, Inuma.
  • Client / Relying Party: an app that relies on the IdP for login.
  • OIDC (OpenID Connect): the open identity standard used (on OAuth 2.0).
  • PKCE: security extension that protects the login exchange.
  • Scope: bucket that controls which claims an app may receive.
  • Claim: a piece of identity info (name, email, unit, role, …).
  • Access token / ID token: prove API access and who the user is.
  • Public client: browser/native app using PKCE with no client secret.
  • Confidential client: server app that authenticates with a client secret.
  • Trusted client: first-party UR app that can skip the consent screen.

Technical reference: OIDC_SSO_README.md ·
Client example: examples/oidc-client-react

About

UNIVERSITY OF RWANDA SINGLE SIGN ON OPTION

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors