Watch
1
Fork
You've already forked cas
0
a wrapper for the central authentication service of unilim, easily pluggable to any other librairies. https://cas.unilim.fr
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-01 08:11:26 +02:00
.forgejo/workflows fix(ci): npm requires public access 2026-08-14 08:42:16 +02:00
examples refactor: split native, npm and wasm bindings for external 2026-08-11 10:26:16 +03:00
src docs: unslopify documentation 2026-08-15 15:35:58 +02:00
tests chore: initialize 2026-06-30 06:57:39 +02:00
.gitattributes chore: initialize 2026-06-30 06:57:39 +02:00
.gitignore refactor: split native, npm and wasm bindings for external 2026-08-11 10:26:16 +03:00
bun.lock refactor: split native, npm and wasm bindings for external 2026-08-11 10:26:16 +03:00
Cargo.lock chore: release v1.0.1 2026-08-15 15:36:25 +02:00
Cargo.toml chore: update package meta 2026-09-01 08:11:26 +02:00
LICENSE.md chore: initialize 2026-06-30 06:57:39 +02:00
package.json refactor: split native, npm and wasm bindings for external 2026-08-11 10:26:16 +03:00
README.md docs: unslopify documentation 2026-08-15 15:35:58 +02:00
tsconfig.json refactor: split native, npm and wasm bindings for external 2026-08-11 10:26:16 +03:00

cas.unilim.fr

npm crates.io docs.rs

Client for the Central Authentication Service of Unilim, the University of Limoges.

It talks to the LemonLDAP::NG portal at cas.unilim.fr and handles login, 2FA, session persistence, service tickets and OAuth2.

Usage

First login, with 2FA

Rust JS/TS
use unilim_cas::CAS;

let mut auth = CAS::initialize(&username, &password).await?;

if !auth.solved {
  if auth.is_totp_available {
    auth.solve_with_totp(&code).await?;
  }
  else if auth.is_email_available {
    auth.send_email_code().await?;
    auth.solve_with_email_code(&code).await?;
  }
}

let cas = auth.finish().await?;
import { CAS } from "@unilim/cas";

const auth = await CAS.initialize(username, password);

if (!auth.solved) {
  if (auth.isTotpAvailable) {
    await auth.solveWithTotp(code);
  }
  else if (auth.isEmailAvailable) {
    await auth.sendEmailCode();
    await auth.solveWithEmailCode(code);
  }
}

const cas = await auth.finish();

finish() registers our "browser" on the portal.

Restoring a session, bypassing 2FA

To be able to do this you should've stored the following values.

  • cas.connection (llngconnection persistence cookie)
  • cas.key (TOTP secret linked to that cookie)
Rust JS/TS
let cas = CAS::restore(
  &username,
  &password,
  &connection, // = cas.connection
  &key         // = cas.key
).await?;
const cas = await CAS.restore(
  username,
  password,
  connection, // = cas.connection
  key         // = cas.key
);

A raw lemonldap session cookie can also be wrapped with CAS::temporary(cookie). Such a session cannot be restored.

Forge service tickets

The returned URL is the login route of the service with a ticket=ST-... query parameter. Requesting it logs you into the service.

Rust JS/TS
use unilim_cas::Services;

let url = cas
  .service(Services::CommunityIut)
  .await?;
import { Services } from "@unilim/cas";

const url = await cas.service(
  Services.CommunityIut
);

Authorize OAuth2

Rust JS/TS
use unilim_cas::OAuth2;

let client = OAuth2::new(
  client_id,
  callback_url,
  scopes,
);

let callback = cas
    .authorize(&client, false, "state")
    .await?;

let tokens = cas
    .tokenize(&callback, &client, false)
    .await?;

let user = cas.userinfo(&tokens).await?;
import { OAuth2 } from "@unilim/cas";

const client = new OAuth2(
  clientId,
  callbackUrl,
  scopes,
);

const callback = await cas.authorize(
  client, false, "state",
);

const tokens = await cas.tokenize(
  callback, client, false,
);

const user = await cas.userinfo(tokens);

License

GPL-3.0-or-later, see LICENSE.md. Not affiliated with the University of Limoges.