Full-featured Node.js library for the SchoolSoft platform (sms.schoolsoft.se).
Typed, dependency-light, and easy to use from simple scripts to production apps.
npm install @elias4044/ssp-nodeThe straightforward way to log in. Posts credentials to SchoolSoft's login form and gets session cookies back.
import { SchoolsoftClient } from '@elias4044/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 weekUses 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 '@elias4044/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();For apps where the user logs in through a browser or WebView.
import { SchoolsoftClient } from '@elias4044/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();| 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. |
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 }.
await client.mobileLogin({ username: 'john.doe', password: 'secret', orgid: '18' });Returns MobileLoginResult with { school, accessToken, refreshToken, expiresAt }.
const flow = SchoolsoftClient.startMobileFlow({ school: 'engelska', redirectUri: 'myapp://' });
// flow.authUrl — open in browser
// flow.verifier — store on device
// flow.state — store and verify on callbackawait client.completeMobileFlow(code, flow.verifier);await client.mobileRefresh();
// Automatically uses the stored refresh tokenawait client.mobileExchangeSession(userId, {
orgid: '18', // school org ID
language: 'sw', // 'sw' or 'en'
theme: 'dark',
useros: 'android', // 'android' or 'ios'
});const info = await client.fetchMobileSessionInfo();
// { username, firstName, lastName, email, schoolName, userType, userId }const alive = await client.verifySession(); // returns booleanclient.setSessionCookies('F92FC4EC...', 'd85914fa...', '1');client.setAccessToken(storedToken, storedRefreshToken, storedExpiresAt);All methods below require a valid session (call login() or mobileLogin() + mobileExchangeSession() first).
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.const menu = await client.getLunch(22); // LunchMenu (array of LunchDay)Returns deduplicated, chronologically sorted lessons. Defaults to the current ISO week.
const { lessons, week } = await client.getSchedule();
const { lessons } = await client.getSchedule(22);const assignments = await client.getAssignmentsForWeek(22, 2025);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');Returns all subject rooms enriched with their entities, teachers, and unread entity count.
const subjects = await client.getSubjects();const detail = await client.getSubject('123');
// { subject, overview: { examinations, submissions }, assignments }Scrapes the news feed from the student startpage.
const news = await client.getNews();
// [{ id, title, preview }, ...]Returns upcoming homework and recent test results from the student startpage.
const { homework, tests } = await client.getStartpage();Returns the list of students in the user's class.
const students = await client.getClassStudents();
// [{ name, email, address }, ...]Returns all schools registered on SchoolSoft, sorted alphabetically. Results are cached for 1 hour.
const schools = await client.getSchools();
// [{ id: 'engelska', name: 'Engelska Skolan ...' }, ...]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 '@elias4044/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');import { schoolsoftFetch, ssUrl } from '@elias4044/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);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();- 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.