Introduction
This article explains a real example of the SSO flow from Anthology Blackboard to a Custom Learning Tool (BonuspointLearningTool.sg). The SSO flow follows OpenID Connect using JWT. The same pattern can be applied to any Custom Learning Tool that is SSO-integrated with Blackboard.
For security, sensitive encoded strings and key values are masked while preserving original length.
0) Entry and callback URLs in this flow
- BonuspointLearningTool OIDC login entry:
https://api.learningtool.bonuspoint.info/lti/oidc/login- BonuspointLearningTool frontend callback:
https://learningtool.bonuspoint.info/sso-callback?token=<BonuspointLearningToolSessionToken>
These two are in different stages:
– /lti/oidc/login is LMS-to-tool OIDC initiation
– /sso-callback?token=... is tool backend redirect to frontend after launch verification
1) Token structure and cryptography clarification
Original point kept: “token has 3 parts separated by dot (.)” — correct.
For a JWT:
– Part 1: header
– Part 2: payload
– Part 3: signature
Important correction:
– These parts are Base64URL encoded (not standard Base64 wording in strict JWT terms).
– Signature segment is also Base64URL text of signature bytes.
Example session token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImRvbmd6aGkueWFuZ0Bib251c3BvaW50LmluZm8iLCJyb2xlIjoiYWRtaW4iLCJpZCI6IjY5NTdiOGY5NTRmOGQ0MDA0NjhlYmU1OSIsInNjaG9vbElkIjoiNjkyZDk0YzllYmEyZDgwMDE5YmY0NjliIiwiY291cnNlSWQiOiI2OTU3YjA1M2E0MWVkZjAwNDc4MjQ1NzciLCJjb3Vyc2VOYW1lIjoiTklFX1RFU1RfQVBQTE******************************************************************************************************************************
Decoded header:
– {"alg":"HS256","typ":"JWT"}
Decoded payload:
– {"email":"dongzhi.yang@bonuspoint.info","role":"admin","id":"6957b8f954f8d400468ebe59","schoolId":"692d94c9eba2d80019bf469b","courseId":"6957b053a41edf0047824577","courseName":"NIE_TEST_APPLETREE","time":1772912607514,"iat":1772912607,"exp":1773344607}
Signature math
For HS256 token signing:
signature = HMACSHA256(base64url(header) + "." + base64url(payload), secret)
Then JWT stores base64url(signature) as segment 3.
2) Two JWT contexts in this integration
A) Platform launch id_token (Blackboard/Anthology -> BonuspointLearningTool)
- Verified by BonuspointLearningTool backend using platform JWKS public keys
- RS256 verification flow in code path
- Validation includes issuer, audience, nonce, expiry, etc.
B) BonuspointLearningTool app session token (BonuspointLearningTool backend -> frontend/API)
- Generated by BonuspointLearningTool backend using session secret (
helpers/jwt.js) - Verified by BonuspointLearningTool backend on API requests (
middlewares/authentication.js) - This is issuer-and-verifier both BonuspointLearningTool (shared secret model)
Original point kept and corrected:
– This is different from RS256/ES256 asymmetric verification.
– Verification is signature checking, not decryption.
3) Credential mapping
LTI_CLIENT_ID = Application IDANTHOLOGY_APPLICATION_KEY = Application KeyANTHOLOGY_APPLICATION_SECRET = LTI_CLIENT_SECRET = Application Secret
Values currently listed in original source:
– Application ID: 68c75d43-9477-4060-8750-3***********
– Application Key: 691c7d94-09a2-4714-9329-6***********
– Secret: EOU9tV95HjgBZkMWwUubeH**********
Security note:
– Keep these in secret storage/env vars; avoid public publication.
4) End-to-End SSO Sequence
Step 1 — User clicks tool in Blackboard
- Browser opens Blackboard tool link (launch link / placement page context)
- Blackboard prepares LTI launch context
Step 2 — Blackboard calls BonuspointLearningTool OIDC login endpoint
- Request to:
https://api.learningtool.bonuspoint.info/lti/oidc/login- Blackboard provides parameters such as:
issclient_idlogin_hintlti_message_hinttarget_link_urilti_deployment_id
Step 3 — BonuspointLearningTool backend validates and creates temporary launch session
- Validates issuer and client id against configured values
- Generates:
statenonce- Stores state/nonce in temporary LTI session storage
Step 4 — BonuspointLearningTool redirects browser to Anthology OIDC auth endpoint
- 302 redirect to:
https://developer.anthology.com/api/v1/gateway/oidcauth- Includes:
response_type=id_tokenscope=openidresponse_mode=form_postclient_idredirect_uri=https://api.learningtool.bonuspoint.info/lti/oidc/launchstatenonceprompt=none- forwarded
login_hint - forwarded
lti_message_hint(if present)
Step 5 — Anthology/Blackboard returns launch result to BonuspointLearningTool
- Browser receives an auto-submitting form (
response_mode=form_post) - POST to:
https://api.learningtool.bonuspoint.info/lti/oidc/launch- Form fields include:
id_tokenstate
Step 6 — BonuspointLearningTool verifies platform id_token
- Decodes token header, reads
kid - Gets platform keys from JWKS endpoint:
https://developer.anthology.com/.well-known/jwks.json- Selects matching key by
kid - Verifies RS256 signature and validates claims (
iss,aud, nonce, expiry)
Step 7 — BonuspointLearningTool user/course processing and sync
- Finds/creates user
- Updates LTI context
- Finds/creates class/course mapping
- If needed, calls Blackboard token endpoint for API-based membership sync:
https://ntulearntst.ntu.edu.sg/learn/api/public/v1/oauth2/token- Uses application key + secret for that server-to-server API token
Step 8 — BonuspointLearningTool generates BonuspointLearningTool session token
- Uses backend session secret (
helpers/jwt.js) - Sets cookie and redirects user to frontend callback:
https://learningtool.bonuspoint.info/sso-callback?token=<BonuspointLearningToolSessionToken>
Step 9 — Frontend callback and API authentication
- Frontend decodes token payload for context routing
- Frontend stores auth context/token and sends GraphQL/API requests with bearer token
- Backend verifies bearer token in middleware
- Frontend navigates user to role-appropriate page (
home,admin-dashboard,school-dashboard, etc.)
5) Query/Form Parameter Purpose Table
iss: identifies trusted platform issuerclient_id: identifies BonuspointLearningTool tool registration in LMSlogin_hint: opaque LMS-provided hint for launch/user continuitylti_message_hint: opaque LMS launch context hinttarget_link_uri: intended tool launch target URLlti_deployment_id: specific LMS deployment identifier for this tool installstate: anti-CSRF + transaction correlationnonce: replay protection for id_tokenid_token: signed platform assertion containing launch/user/role/context claimskid: key id in JWT header used to choose proper verification key from JWKS
6) Original conversational summary
- Browser/User -> Blackboard: user wants to open BonuspointLearningTool tool
- Blackboard -> BonuspointLearningTool: sends OIDC launch initiation with known client id and hints
- BonuspointLearningTool -> Blackboard/Browser: returns redirect to Anthology OIDC with generated state/nonce
- Browser -> Anthology: continues authentication launch
- Anthology + Blackboard runtime prepare signed
id_token - Browser -> BonuspointLearningTool launch callback: submits
id_token+state - BonuspointLearningTool -> Anthology runtime: fetches JWKS public keys and verifies signature
- BonuspointLearningTool -> Browser: after validation, returns BonuspointLearningTool app session token and redirects to frontend
- BonuspointLearningTool frontend -> Browser: initializes authenticated experience
Corrections applied to original wording:
– Not “decryption” of JWT signature; this is signature verification
– JWKS keys are platform-published rotating keys, not per-user “dynamic session key” semantics
– BonuspointLearningTool app session token is issued by BonuspointLearningTool backend and then used for BonuspointLearningTool API authorization
7) Mermaid sequence

8) Additional implementation notes from code
- Backend sets
httpOnlycookie for token during redirect flow. - Frontend callback also processes token from query and stores token/context for app usage.
- Membership sync logic can use Blackboard REST API and token endpoint credentials.
9) Final concise takeaway
- Platform launch token validation (LTI/OIDC): asymmetric verification via JWKS (RS256 path)
- BonuspointLearningTool app token validation: shared-secret signing/verification within BonuspointLearningTool
- Security of this flow depends on strict validation of state, nonce, issuer, audience, signature key id (
kid), and expiry.
Leave a Reply