unilim-cas (1.0.1)

Published 2026-08-15 13:39:40 +00:00 by Mikkel ALMONTE--RINGAUD in unilim/cas

Installation

[registries.forgejo]
index = "sparse+" # Sparse index
# index = "" # Git

[net]
git-fetch-with-cli = true
cargo add unilim-cas@1.0.1 --registry forgejo

About this package

A purrfect CAS authentication wrapper for Unilim.

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.

Dependencies

ID Version
rikka ^0.1
scraper ^0.21
serde ^1
thiserror ^2
totp-rs ^5
url ^2
web-time ^1
anyhow ^1
dotenvy ^0.15
inquire ^0.7
tokio ^1
getrandom ^0.3
js-sys ^0.3
lol_alloc ^0.4
tsify-next ^0.5
wasm-bindgen ^0.2
wasm-bindgen-futures ^0.4

Keywords

unilim cas authentication api wrapper
Details
Cargo
2026-08-15 13:39:40 +00:00
6
Mikkel ALMONTE--RINGAUD <contact@vexcited.com>
GPL-3.0-or-later
45 KiB
Assets (1)
Versions (2) View all
1.0.1 2026-08-15
1.0.0 2026-08-14