Skip to content

elias4044/ssp-node

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SchoolSoft+ Logo

Schoolsoft+ Node

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.

Documentation MIT License TypeScript 5 npm Node ≥ 18



Installation

npm install @elias4044/ssp-node

Quick 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 '@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 week

Mobile 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 '@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();

Mobile login (browser / WebView flow)

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();

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' = staff

Returns 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 callback

client.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 token

client.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 boolean

client.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 '@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');

Making raw requests

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);

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 school slug is the part of the URL between sms.schoolsoft.se/ and the next /. Use getSchools() to look it up by school name.

About

NPM Library for intereacting with the Schoolsoft API. Fully documentated and easy to use.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors