npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@elias4044/ssp-node

v1.0.0

Published

Node.js library for interacting with the Schoolsoft platform (sms.schoolsoft.se)

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