Skip to content

Sign-in and LTI

Hanami accepts an A+ personal API token in two sign-in flows:

  • The token prompt lets a user paste the token from their A+ profile.
  • An A+ LTI 1.1 menu launch can carry the token as custom_user_api_token when API access is enabled for the LTI service.

Both flows send the A+ token once from SvelteKit to POST /internal/frontend/sessions. Ktor validates it, resolves the A+ identity, encrypts the token, and returns a random Hanami session identifier. SvelteKit stores that identifier in the hanami_session cookie. The raw A+ token is not written to a browser cookie.

The LTI launch is a top-level cross-site POST. SvelteKit admits form posts only from the exact HTTP(S) origin configured by APLUS_URL, then validates the OAuth 1.0 signature, nonce, timestamp, consumer key, and signed launch URL before exchanging the A+ token. The signing method is HMAC-SHA1 because that is what the A+ LTI 1.1 integration uses.

The origin allowlist limits which site can reach the launch handler; the OAuth signature authenticates the launch. Other browser mutations use SvelteKit remote functions and the normal same-origin policy.

Create an LTI 1.1 service in the A+ site administration and grant it API access. Configure the same values in Hanami:

  • LTI_CONSUMER_KEY
  • LTI_CONSUMER_SECRET
  • APLUS_URL

Add the service to each course menu with the label Hanami and the postcard-heart icon. Ktor discovers a launch URL for each course. Set LTI_MENU_LABEL if the menu uses a different label.

The consumer key and secret must be configured together in SvelteKit. Production rejects the well-known local development secret unless LTI_ALLOW_WEAK_SECRET=true is set explicitly.

Open Hanami as a full page, not in an iframe. The session cookie uses SameSite=Lax, and modern browsers restrict third-party cookie use inside cross-site frames.

The first A+ launch may show a consent page because A+ is sending identity data and API access to another service. Users can allow automatic continuation for later launches.

Check that the course menu contains the configured service and that its label matches LTI_MENU_LABEL. Then use Refresh from A+ in course settings.

Check that the consumer key and secret match the A+ site service. The reverse proxy must forward the public scheme and host. Set LTI_LAUNCH_URL only when the URL signed by A+ differs from the URL SvelteKit reconstructs from forwarded headers.

Use a full-page menu link and accept the first-launch consent page. Confirm that FRONTEND_ORIGIN is the public Hanami origin and that the browser can reach both sites.

The session exchange is shared, so the fault is in the LTI service, menu item, signature, nonce, or launch URL. Check the SvelteKit log by request ID without logging the launch body or token.

For local setup, see Local A+.