Registering a NUMBAS-LTI server with Anthology

24 views
Skip to first unread message

David Martin

unread,
Sep 25, 2025, 3:48:54 AMSep 25
to Numbas Users
I have just installed NUMBAS-LTI via docker on RHEL9 and it seems to run fine. My next step is to register it with Anthology so I can add it to our blackboard instance.

Couple of things: 
1. The link to anthology in the server is now broken. You have to find the right page at developer.anthology.com.
2. When I attempt to register I presume I should select the 'My Integration supports LTI 1.3' but then I get requests for a bunch of information I can't find reference to in the docs.

Login initiation URL
Tool Redirect URL(s)
Tool JWKS URL
The default SIgning Algorithm is RS256
Are there any custom parameters to set?

Any help would be appreciated

..d

Dr David Martin
 

Johan Slabbert

unread,
Sep 25, 2025, 4:03:38 AMSep 25
to numbas...@googlegroups.com
Good day

I believe it is a 3 part process



c) In your Blackboard Instance you then : Register LTI 1.3/Advantage Tool where you add the ClientID you created in b:

image.png



Johan Slabbert
Educational Technology Project Manager
BEng (Pret), BEng Hons (Pret), MIT (Pret), MEng(Pret)

Tel +27 (0)12 420 3825
Fax +27 (0)12 420 3697
Email johan.s...@up.ac.za
www.up.ac.za

Department for Education Innovation 
Room 3-34, IT Building, Hatfield Campus
University of Pretoria, Private Bag X20
Hatfield 0028, South Africa




--
You received this message because you are subscribed to the Google Groups "Numbas Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to numbas-users...@googlegroups.com.
To view this discussion, visit https://groups.google.com/d/msgid/numbas-users/91bcefd6-0c22-4194-b627-6fd695fe5b2cn%40googlegroups.com.

This message and attachments are subject to a disclaimer.
Please refer to http://upnet.up.ac.za/services/it/documentation/docs/004167.pdf 
for full details.

David Martin

unread,
Sep 25, 2025, 4:11:01 AMSep 25
to numbas...@googlegroups.com
The instructions are incomplete as per my email. 

..d

You received this message because you are subscribed to a topic in the Google Groups "Numbas Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/numbas-users/VGjF5zCA7v0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to numbas-users...@googlegroups.com.
To view this discussion, visit https://groups.google.com/d/msgid/numbas-users/CABP1u53JqsesTuzrZPBiFBwn5iukoa60LmKKgm3ZAHVNrJwE3Q%40mail.gmail.com.

David Martin

unread,
Sep 25, 2025, 7:10:17 AMSep 25
to numbas...@googlegroups.com
OK, it looks like the broken link mislead me. 

Connect to Blackboard

Blackboard expects most LTI tools to run on a single domain, which serves every institution using it.

Because each institution runs their own instance of the Numbas LTI tool, each instance must be registered separately with Anthology.

  1. Register this server as an application with Anthology.
  2. Create a dynamic registration token.

    In the Anthology Developer portal, use Dynamic Registration with the token URL you created, to initiate tool registration.

    Record the Application ID and the Application Key that were created.


I was under the impression that I had to first register with anthology (step 1), then do the next steps as the page linked was 404ing.

Step 2 I then read as a title  and a single step on anthology where it is in fact multiple steps. a) create a dynamic registration token (on th elocal LTI server) and then step 2b is on the anthology site. 
The application key is not obvious, you have to select the 'manage keys' option fromt eh trhee dots next to the application registration.

So far so good - need to wait on my IT colleagues for the next step.

Best wishes

..d

David Martin

unread,
Nov 3, 2025, 10:38:06 AM (3 days ago) Nov 3
to Numbas Users
I get a 500 server error when trying to register the app at Anthology. When I add the app in Anthology it asks me for the dynamic registration token. This gives a popup asking if I wish to register. I click register and this prompts a 500 server error. Is there any hint as to how to check the logs to find the error? I am using Docker on RHEL 9.

..d

Christian Lawson-Perfect

unread,
Nov 4, 2025, 7:47:48 AM (2 days ago) Nov 4
to numbas...@googlegroups.com
Hi David,
Could you try running `docker container logs` on the daphne container? 

David Martin

unread,
Nov 4, 2025, 9:24:32 AM (2 days ago) Nov 4
to numbas...@googlegroups.com
django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: 'numbas-sls-wp1.dundee.ac.uk'. You may need to add 'numbas-sls-wp1.dundee.ac.uk' to ALLOWED_HOSTS.
Internal Server Error: /
Invalid HTTP_HOST header: 'numbas-sls-wp1.dundee.ac.uk'. You may need to add 'numbas-sls-wp1.dundee.ac.uk' to ALLOWED_HOSTS.
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/utils/deprecation.py", line 128, in __call__
    response = self.process_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/middleware/common.py", line 48, in process_request
    host = request.get_host()
           ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/http/request.py", line 151, in get_host
    raise DisallowedHost(msg)
django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: 'numbas-sls-wp1.dundee.ac.uk'. You may need to add 'numbas-sls-wp1.dundee.ac.uk' to ALLOWED_HOSTS.
Internal Server Error: /owa/
Invalid HTTP_HOST header: 'numbas-sls-wp1.dundee.ac.uk'. You may need to add 'numbas-sls-wp1.dundee.ac.uk' to ALLOWED_HOSTS.
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/utils/deprecation.py", line 128, in __call__
    response = self.process_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/middleware/common.py", line 48, in process_request
    host = request.get_host()
           ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/http/request.py", line 151, in get_host
    raise DisallowedHost(msg)
django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: 'numbas-sls-wp1.dundee.ac.uk'. You may need to add 'numbas-sls-wp1.dundee.ac.uk' to ALLOWED_HOSTS.
Internal Server Error: /
Invalid HTTP_HOST header: '172.18.0.5:8700'. You may need to add '172.18.0.5' to ALLOWED_HOSTS.
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/utils/deprecation.py", line 128, in __call__
    response = self.process_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/middleware/common.py", line 48, in process_request
    host = request.get_host()
           ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/http/request.py", line 151, in get_host
    raise DisallowedHost(msg)
django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: '172.18.0.5:8700'. You may need to add '172.18.0.5' to ALLOWED_HOSTS.
Internal Server Error: /robots.txt

Looking at this it seems that the config requires the internal hostname for the VM as well as the outwardly facing FQDN. I'll try adding env('HOSTNAME') to that in settings.py and restarting the  container

..d

David Martin

unread,
Nov 4, 2025, 9:32:28 AM (2 days ago) Nov 4
to numbas...@googlegroups.com
That now gives me a new error when trying Dynamic configuration

Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler
    raise exc_info[1]
  File "/usr/local/lib/python3.12/site-packages/django/core/handlers/exception.py", line 42, in inner
    response = await get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler
    raise exc_info[1]
  File "/usr/local/lib/python3.12/site-packages/django/core/handlers/base.py", line 253, in _get_response_async
    response = await wrapped_callback(
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 439, in __call__
    ret = await asyncio.shield(exec_coro)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/asgiref/current_thread_executor.py", line 40, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 493, in thread_handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/views/generic/base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/utils/decorators.py", line 48, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper
    return view_func(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/numbas-lti-provider/numbas_lti/views/lti_13.py", line 391, in dispatch
    return super().dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/views/generic/base.py", line 143, in dispatch
    return handler(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/views/generic/edit.py", line 258, in post
    return self.form_valid(form)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/numbas-lti-provider/numbas_lti/views/lti_13.py", line 426, in form_valid
    lti_tool = registration.register()
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/pylti1p3/dynamic_registration.py", line 283, in register
    assert tool_spec in openid_registration, \
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: The OpenID registration is not an LTI tool configuration

David Martin

unread,
4:33 AM (11 hours ago) 4:33 AM
to numbas...@googlegroups.com
Tried a couple of things. One was to open up allowed hosts with my local domain as 134.36.0.0/16

Then making sure I had actually completed the App ID/client ID registration

I then get the same nonce error 

Headers from Daphne

172.18.0.5:47662 - - [06/Nov/2025:09:05:56] "GET /consumers/1" 200 3817
172.18.0.5:34872 - - [06/Nov/2025:09:06:05] "GET /lti13/login/?iss=https%3A%2F%2Fblackboard.com&login_hint=https%253A%252F%252Fdundee-staging.blackboard.com%252Fwebapps%252Fblackboard%252Fexecute%252Fblti%252FlaunchPlacement%253Fcmd%253Dauthenticate%2526course_id%253D_81212_1%2Cc248f60be70545a2a2259f1039aab68f%2Cd2613617ee75460cad98300c853d7341&target_link_uri=https%3A%2F%2Fnumbas.dundee.ac.uk%2Flti13%2Flaunch%2F&lti_message_hint=eyJjdXN0b21QYXJhbXMiOnt9LCJvcGVuSW5MaWdodEJveCI6ZmFsc2UsImZyb21VbHRyYSI6dHJ1ZSwiaW5saW5lTW9kZSI6ZmFsc2UsImhpZGVEb2N1bWVudCI6ZmFsc2UsInBsYWNlbWVudElkIjoiXzEzMTFfMSIsInRhcmdldE92ZXJyaWRlIjpudWxsLCJmcm9tR3JhZGVDZW50ZXIiOmZhbHNlLCJvcGVuTmV3V2luZG93IjpmYWxzZSwiZGVlcExpbmtMYXVuY2giOnRydWUsInBhcmVudENvbnRlbnRJZCI6IiIsInJlc291cmNlTGlua0lkIjoiXzc1NTExMzFfMSIsImNvdXJzZUlkIjoiXzgxMjEyXzEiLCJncm91cElkIjpudWxsLCJjb250ZW50SWQiOiJfNzU1MTEzMV8xIiwiZGVwbG95bWVudElkIjoiNDhiOTA1YzAtYjdiYS00NmI1LWFlM2EtY2FjYzJkZDQwNDI2IiwicG9zaXRpb24iOjUsInRhcmdldExpbmtVcmwiOiJodHRwczovL251bWJhcy5kdW5kZWUuYWMudWsvbHRpMTMvbGF1bmNoLyJ9&lti_deployment_id=48b905c0-b7ba-46b5-ae3a-cacc2dd40426&client_id=ab972195-c99f-4e84-ae76-bc344d14cd2a&lti_storage_target=lti_storage_frame" 200 4229
172.18.0.5:34880 - - [06/Nov/2025:09:06:05] "GET /lti13/login/?iss=https%3A%2F%2Fblackboard.com&login_hint=https%253A%252F%252Fdundee-staging.blackboard.com%252Fwebapps%252Fblackboard%252Fexecute%252Fblti%252FlaunchPlacement%253Fcmd%253Dauthenticate%2526course_id%253D_81212_1%2Cc248f60be70545a2a2259f1039aab68f%2Cd2613617ee75460cad98300c853d7341&target_link_uri=https%3A%2F%2Fnumbas.dundee.ac.uk%2Flti13%2Flaunch%2F&lti_message_hint=eyJjdXN0b21QYXJhbXMiOnt9LCJvcGVuSW5MaWdodEJveCI6ZmFsc2UsImZyb21VbHRyYSI6dHJ1ZSwiaW5saW5lTW9kZSI6ZmFsc2UsImhpZGVEb2N1bWVudCI6ZmFsc2UsInBsYWNlbWVudElkIjoiXzEzMTFfMSIsInRhcmdldE92ZXJyaWRlIjpudWxsLCJmcm9tR3JhZGVDZW50ZXIiOmZhbHNlLCJvcGVuTmV3V2luZG93IjpmYWxzZSwiZGVlcExpbmtMYXVuY2giOnRydWUsInBhcmVudENvbnRlbnRJZCI6IiIsInJlc291cmNlTGlua0lkIjoiXzc1NTExMzFfMSIsImNvdXJzZUlkIjoiXzgxMjEyXzEiLCJncm91cElkIjpudWxsLCJjb250ZW50SWQiOiJfNzU1MTEzMV8xIiwiZGVwbG95bWVudElkIjoiNDhiOTA1YzAtYjdiYS00NmI1LWFlM2EtY2FjYzJkZDQwNDI2IiwicG9zaXRpb24iOjUsInRhcmdldExpbmtVcmwiOiJodHRwczovL251bWJhcy5kdW5kZWUuYWMudWsvbHRpMTMvbGF1bmNoLyJ9&lti_deployment_id=48b905c0-b7ba-46b5-ae3a-cacc2dd40426&client_id=ab972195-c99f-4e84-ae76-bc344d14cd2a&lti_storage_target=lti_storage_frame&lti1p3_new_window=1" 302 -
Reply all
Reply to author
Forward
0 new messages