@elias4044/ssp-node
v1.0.0
Published
Node.js library for interacting with the Schoolsoft platform (sms.schoolsoft.se)
Maintainers
Readme
ssp-node
A Node.js library for interacting with the Schoolsoft platform (sms.schoolsoft.se).
Supports two login methods, all major data endpoints, and is designed to be simple out of the box while giving you full control when you need it.
Requirements: Node.js 18 or later.
Installation
npm install ssp-nodeQuick start
Simple login (username + password)
The straightforward way to log in. Posts credentials to SchoolSoft's login form and gets session cookies back.
import { SchoolsoftClient } from 'ssp-node';
const client = new SchoolsoftClient({ school: 'engelska' });
await client.login({ username: 'john.doe', password: 'mypassword' });
const lunch = await client.getLunch(22); // week 22
const schedule = await client.getSchedule(); // current weekMobile login (automated)
Uses SchoolSoft's OAuth2 + PKCE flow — the same way the official app authenticates. Gives you a short-lived access token and a long-lived refresh token. You then exchange the access token for session cookies to use the API.
import { SchoolsoftClient } from 'ssp-node';
const client = new SchoolsoftClient({ school: 'engelska' });
// Step 1: get the access token and refresh token
await client.mobileLogin({ username: 'john.doe', password: 'mypassword' });
// Step 2: exchange the access token for session cookies
// Optionally fetch the userId first for a more reliable exchange
const sessionInfo = await client.fetchMobileSessionInfo();
await client.mobileExchangeSession(sessionInfo?.userId);
// Now use the API normally
const subjects = await client.getSubjects();Mobile login (browser / WebView flow)
For apps where the user logs in through a browser or WebView.
import { SchoolsoftClient } from 'ssp-node';
// Generate the auth URL and PKCE verifier
const flow = SchoolsoftClient.startMobileFlow({
school: 'engelska',
redirectUri: 'com.myapp://auth', // your app's deep-link
});
console.log(flow.authUrl); // open this in a browser
// Store flow.verifier and flow.state on the device
// After the user logs in, SchoolSoft redirects to:
// com.myapp://auth?code=XXXX&state=YYYY
// Verify that state matches flow.state, then:
const client = new SchoolsoftClient({ school: 'engelska' });
await client.completeMobileFlow(code, flow.verifier);
const sessionInfo = await client.fetchMobileSessionInfo();
await client.mobileExchangeSession(sessionInfo?.userId);
const news = await client.getNews();API reference
new SchoolsoftClient(options?)
| Option | Type | Default | Description |
|---|---|---|---|
| school | string | "engelska" | School slug from the URL, e.g. "engelska" or "carlwahren". Use getSchools() to find yours. |
| userAgent | string | Built-in UA | Override the User-Agent header sent with all requests. |
Authentication
client.login(options) — simple login
await client.login({ username: 'john.doe', password: 'secret', usertype: '1' });
// usertype: '1' = student (default), '2' = guardian, '3' = staffReturns SimpleLoginResult with { school, username, cookieHeader, jsessionid, hash, usertype }.
client.mobileLogin(options) — automated mobile login
await client.mobileLogin({ username: 'john.doe', password: 'secret', orgid: '18' });Returns MobileLoginResult with { school, accessToken, refreshToken, expiresAt }.
SchoolsoftClient.startMobileFlow(options) — generate browser auth URL
const flow = SchoolsoftClient.startMobileFlow({ school: 'engelska', redirectUri: 'myapp://' });
// flow.authUrl — open in browser
// flow.verifier — store on device
// flow.state — store and verify on callbackclient.completeMobileFlow(code, verifier) — finish the browser flow
await client.completeMobileFlow(code, flow.verifier);client.mobileRefresh() — refresh the access token
await client.mobileRefresh();
// Automatically uses the stored refresh tokenclient.mobileExchangeSession(userId?, options?) — get session cookies from access token
await client.mobileExchangeSession(userId, {
orgid: '18', // school org ID
language: 'sw', // 'sw' or 'en'
theme: 'dark',
useros: 'android', // 'android' or 'ios'
});client.fetchMobileSessionInfo() — get user info from access token
const info = await client.fetchMobileSessionInfo();
// { username, firstName, lastName, email, schoolName, userType, userId }client.verifySession() — check if the session is still active
const alive = await client.verifySession(); // returns booleanclient.setSessionCookies(jsessionid, hash, usertype?) — restore a saved session
client.setSessionCookies('F92FC4EC...', 'd85914fa...', '1');client.setAccessToken(accessToken, refreshToken?, expiresAt?) — restore a saved token
client.setAccessToken(storedToken, storedRefreshToken, storedExpiresAt);client.logout() — clear all session state
Data endpoints
All methods below require a valid session (call login() or mobileLogin() + mobileExchangeSession() first).
client.getSession()
Returns the full session info from SchoolSoft including user name, school, user type, and more.
const session = await client.getSession();
// session.user.firstName, session.organization.name, etc.client.getLunch(week)
const menu = await client.getLunch(22); // LunchMenu (array of LunchDay)client.getSchedule(week?)
Returns deduplicated, chronologically sorted lessons. Defaults to the current ISO week.
const { lessons, week } = await client.getSchedule();
const { lessons } = await client.getSchedule(22);client.getAssignmentsForWeek(week, year)
const assignments = await client.getAssignmentsForWeek(22, 2025);client.getAssignment(id, type?)
Fetches full details for an assignment or planning entry, including sections, assessment, and grading.
const detail = await client.getAssignment(12345);
const planning = await client.getAssignment(67890, 'planning');client.getSubjects()
Returns all subject rooms enriched with their entities, teachers, and unread entity count.
const subjects = await client.getSubjects();client.getSubject(id)
const detail = await client.getSubject('123');
// { subject, overview: { examinations, submissions }, assignments }client.getNews()
Scrapes the news feed from the student startpage.
const news = await client.getNews();
// [{ id, title, preview }, ...]client.getStartpage()
Returns upcoming homework and recent test results from the student startpage.
const { homework, tests } = await client.getStartpage();client.getClassStudents()
Returns the list of students in the user's class.
const students = await client.getClassStudents();
// [{ name, email, address }, ...]client.getSchools() — no auth required
Returns all schools registered on SchoolSoft, sorted alphabetically. Results are cached for 1 hour.
const schools = await client.getSchools();
// [{ id: 'engelska', name: 'Engelska Skolan ...' }, ...]Advanced usage
Every function used internally by SchoolsoftClient is also exported, so you can use them directly without the class if you prefer a more functional style.
import {
simpleLogin,
mobileLogin,
getLunch,
getSchedule,
isoWeek,
schoolsoftFetch,
ssUrl,
} from 'ssp-node';
const session = await simpleLogin('engelska', { username: 'john.doe', password: 'secret' });
const menu = await getLunch('engelska', session.cookieHeader, isoWeek(new Date()), 'my-agent/1.0');Making raw requests
import { schoolsoftFetch, ssUrl } from 'ssp-node';
const result = await schoolsoftFetch(
ssUrl('engelska', '/rest-api/some/endpoint'),
'engelska',
{
method: 'GET',
headers: { Cookie: cookieHeader, Accept: 'application/json' },
responseType: 'json',
}
);
console.log(result.status, result.data);Token storage example
For apps that need to persist the session across restarts:
// After mobile login, save these values
const tokenData = {
accessToken: client.accessToken,
refreshToken: client.refreshToken,
};
// On the next startup, restore them
client.setAccessToken(tokenData.accessToken, tokenData.refreshToken);
// Then exchange for session cookies
await client.mobileExchangeSession();Notes
- SchoolSoft's access tokens are short-lived (typically 15 minutes). The refresh token lasts much longer.
mobileExchangeSession()automatically refreshes the access token if it appears expired.- HTML-scraping endpoints (
getNews,getStartpage,getClassStudents) depend on SchoolSoft's page structure and may break if SchoolSoft changes their HTML layout. - The
schoolslug is the part of the URL betweensms.schoolsoft.se/and the next/. UsegetSchools()to look it up by school name.
