sso method

Future<void> sso(
  1. PortalServiceCode serviceCode
)

Performs single sign-on (SSO) to authenticate with a target NTUT service.

This method must be called after login to obtain session cookies for other NTUT services (Course Service, Score Service, or I-School Plus).

The SSO process:

  1. Fetches an SSO form from Portal with the service code
  2. Submits the form to the target service
  3. Sets the necessary authentication cookies for that service

All services share the same cookie jar, so SSO only needs to be called once per service during a session.

Throws an Exception if the SSO form is not found (user may not be logged in).

Implementation

Future<void> sso(PortalServiceCode serviceCode) async {
  // Fetch a self-submitting SSO form
  final response = await _portalDio.get(
    'ssoIndex.do',
    queryParameters: {'apOu': serviceCode.code},
  );

  // Parse the HTML to extract the form
  final document = parse(response.data);
  final form = document.querySelector('form[name="ssoForm"]');
  if (form == null) {
    throw Exception('SSO form not found. Are you logged in?');
  }

  // Extract form action and inputs
  final actionUrl = form.attributes['action']!;
  final inputs = form.querySelectorAll('input');
  final formData = <String, dynamic>{
    for (final input in inputs)
      if (input.attributes['name'] != null)
        input.attributes['name']!: input.attributes['value'] ?? '',
  };

  // Prepend the invalid cookie filter interceptor for i-School Plus SSO
  if (serviceCode == PortalServiceCode.iSchoolPlusService) {
    _portalDio.interceptors.insert(0, InvalidCookieFilter());
    _portalDio.transformer = PlainTextTransformer();
  }

  // Submit the SSO form and follow redirects
  // Sets the necessary cookies for the target service
  await _portalDio.post(
    actionUrl,
    data: formData,
    options: Options(contentType: Headers.formUrlEncodedContentType),
  );
}