Authoritative summary of the backend Lambda endpoints for client library development. Aligned with SECURITY_MODEL.md and client_example.py.
- Single-use tokens: Every grading interaction is gated by HMAC-SHA256 tokens issued by
token_generator. Tokens are single-use, expire after 1 hour, and are tied tostudent_id+test_case(usehomework_idastest_casefor grade retrieval). - Rate limiting: Token generation is limited to 3 requests/minute per student.
- Two-token flow: Clients request two tokens per submission:
token1(fetch test) andtoken2(save grade). Grade retrieval also requires two tokens tied tohomework_id+student_id. - Environment-driven secrets:
SYSTEM_SALTis provided via Lambda env var (not config files). Course secret is retrieved from DynamoDBClassestable viacourse_idfilter andsecret_keyvalue. - HTTP Methods:
token_generator: GET (recommended) or POST - for retrieving tokens without side effects- All other endpoints: POST - for submitting data and modifying state
Generates a pair of single-use tokens for a student & test case.
- HTTP Method:
GET(recommended) orPOST - API Gateway Path: typically
/token_generator - Headers:
x-api-key: <api_key>(required if API Gateway API key requirement is enabled) - Query Parameters (for GET) or Request Body (JSON for POST):
student_id(string, required)student_secret(string, required) — typically the student’s ID/secrettest_case(string, required) — test case name/id (usehomework_idwhen requesting tokens for grade lookup)course_name(string, required) — public course identifier
- Processing:
- Rate-limit check (3/min per
student_id). - Looks up
course_secretby scanningClassestable wherecourse_id == course_name, returningsecret_key. - Generates two distinct tokens using HMAC-SHA256 with key
(student_secret + SYSTEM_SALT)and message(student_id + test_case + course_secret + timestamp + nonce). - Stores tokens in
StudentTokenswith statusactive,created_attimestamp, and TTL = 1h. - Updates
StudentRateLimittable to track request count.
- Rate-limit check (3/min per
- Responses:
200:{ "token1": "...", "token2": "..." }429: rate limit exceeded (back off ≥60s)400: malformed payload, missing required fields, or invalid course name
- Notes:
- Tokens are single-use; reuse returns an error at consuming endpoints.
- Tokens expire after 1 hour (enforced via DynamoDB TTL and runtime timestamp checks).
- Token format:
<hmac_hash>.<nonce>.<timestamp>
Orchestrates grading: fetches test case (using token_test), runs grade logic, saves result (using token_save).
- HTTP Method:
POST - API Gateway Path: typically
/grader - Headers:
x-api-key: <api_key>(required if API Gateway API key requirement is enabled) - Request Body (JSON):
homework_id(string, required)student_id(string, required)test_case_id(string, required)secret(string, optional; kept for compatibility)answer(string, required) — base64/dill-serialized payload or plain texttoken_test(string, required) — from token_generator (token1)token_save(string, required) — from token_generator (token2)
- Processing:
- Calls
get_test_caseAPI withhomework_id+token_test. - Deserializes test case code and libraries from base64/dill format.
- Imports required libraries dynamically into grader namespace.
- Executes the test case function against deserialized
answer. - Calls
save_studentAPI withtoken_saveto persist score.
- Calls
- Responses:
200: grading message string (includes score and feedback)400: errors including:- Parse errors (malformed payload)
- Token errors (invalid, expired, already used)
- Fetch errors (test case not found, HTTP 400/401/403)
- Grading errors (execution exceptions)
- Save errors (storage failures)
- Error Details by HTTP Code:
400from get_test_case: Bad request - invalid homework_id or token format401from get_test_case: Unauthorized - invalid API key403from get_test_case: Forbidden - token invalid, expired, or already used
- Notes:
- Both tokens are mandatory in the new security model.
secretis still accepted for backward compatibility but not the primary trust mechanism.- The
deserialize()function handles both base64/dill-encoded and plain text answers.
Returns test case code and required libraries for a homework/test case. Requires a valid single-use token.
- HTTP Method:
POST - API Gateway Path: typically
/GetTestor/get_test_case - Headers:
x-api-key: <api_key>(required if API Gateway API key requirement is enabled) - Request Body (JSON):
homework_id(string, required)token(string, required) — should betoken1from token_generator
- Processing:
- Parses event body (handles both direct JSON and API Gateway wrapped format).
- Verifies token in
StudentTokenstable:- Token exists and has not been used (status ≠ 'used')
- Token has not expired (current_time - created_at ≤ 3600 seconds)
- Token claims match request (student_id and test_case)
- Retrieves test case and libraries from
HomeworksTestCasestable using DynamoDB Table resource. - Marks token as
usedwithused_attimestamp.
- Responses:
200:{ "tests": <serialized_tests>, "libs": <serialized_libs> }400: errors including:- Malformed payload (missing homework_id or token)
- Token not found or already used
- Token has expired
- Token missing student_id or test_case claims
- Homework not found in database
- Notes:
- Test cases and libraries are stored in base64/dill-serialized format.
- Token verification happens before database lookup.
- Tokens are immediately marked as used to prevent replay attacks.
Records a student’s score for a test case. Requires a valid single-use token.
- HTTP Method:
POST - API Gateway Path: typically
/SaveGradeor/save_student - Headers:
x-api-key: <api_key>(required if API Gateway API key requirement is enabled) - Request Body (JSON):
homework_id(string, required)student_id(string, required)test_case_id(string, required)secret(string, required for legacy secret validation)score(number/string, required)max_score(number/string, required)message(string, optional)token(string, required) — should betoken2from token_generator
- Processing:
- Verifies token in
StudentTokenstable:- Token exists and has not been used (status ≠ 'used')
- Token has not expired (current_time - created_at ≤ 3600 seconds)
- Token
student_idclaim matches requeststudent_id - Token
test_caseclaim matches requesttest_case_id
- Retrieves existing submission from
Gradebookto check for secret mismatch. - Writes to
Gradebookwith composite key:homework_id: partition keystudent_submission_id: sort key =student_id + '_' + test_case_id
- Stores
student_score,max_score,timestamp, andsecret. - Marks token as
usedwithused_attimestamp.
- Verifies token in
- Responses:
200: success message with score summary400: errors including:- Malformed payload (missing required fields)
- Token verification failed (not found, expired, used, or claims mismatch)
- Secret mismatch (different secret used for same question)
- Storage errors (DynamoDB write failures)
- Notes:
- Legacy secret validation: if a previous submission exists with a different secret, the request fails.
- Tokens are single-use and immediately marked as used.
Fetches grades for a student. ALL_STUDENTS is disabled. Requires two single-use tokens tied to student_id + homework_id.
- HTTP Method:
POST - API Gateway Path: typically
/grades_lambdaor/grades - Headers:
x-api-key: <api_key>(required if API Gateway API key requirement is enabled) - Request Body (JSON):
homework_id(string, required)request_type(enum: must beSTUDENT_GRADE;ALL_STUDENTS_GRADESis rejected)student_id(string, required)token1(string, required) — token tied tostudent_id+homework_idtoken2(string, required) — second token tied tostudent_id+homework_id
- Processing:
- Validates
request_typeisSTUDENT_GRADE(throws exception forALL_STUDENTS_GRADES). - Retrieves homework metadata from
HomeworksMetadatatable (deadline, max_daily_submissions, total_score). - Verifies both tokens against
StudentTokenstable:- Both tokens exist and have not been used
- Both tokens have not expired
- Both tokens match
student_idandhomework_id
- Marks both tokens as used with
used_attimestamps. - Scans
Gradebooktable for all submissions wherehomework_idmatches andstudent_submission_idbegins withstudent_id. - Serializes response as JSON (not base64/dill).
- Validates
- Responses:
200: JSON serialized grades array plus metadata(grades, deadline, max_daily_submissions, max_score)400: errors including:- Malformed payload
- Unsupported request_type (ALL_STUDENTS_GRADES)
- Token verification failed (not found, expired, used, or claims mismatch)
- Homework metadata not found
- Notes:
- Clients must first call
token_generatorwithtest_case = homework_idto obtaintoken1/token2for this request. - Both tokens are verified and marked used before grade retrieval.
- Uses low-level DynamoDB client for metadata lookup (requires
{'S': value}format). - Uses DynamoDB Table resource for token operations.
- Clients must first call
Creates or updates homework metadata. (If exposed)
- Not covered by token flow; typically admin-only. Refer to deployment-specific policy for access control.
Grading flow (homework test execution)
- Call
token_generatorwith (student_id,student_secret,test_case,course_name). - Receive
token1(tests) andtoken2(save). - Preferred: call
graderwithtoken_test = token1,token_save = token2. - Alternate: call
get_test_casewithtoken = token1, run locally, thensave_studentwithtoken = token2. - On 400 token errors, regenerate; on 429 back off ≥60s.
Grade retrieval flow (student reads their grades)
- Call
token_generatorwith (student_id,student_secret,test_case = homework_id,course_name). - Receive
token1andtoken2(both tied to homework_id). - Call
grades_lambdawithrequest_type = STUDENT_GRADE, supplyingtoken1,token2,student_id, andhomework_id. - Tokens are single-use; regenerate for each lookup.
- Format:
<hmac>.<nonce>.<timestamp> - Key:
student_secret + SYSTEM_SALT - Message:
student_id + test_case + course_secret + timestamp + nonce - TTL: 1 hour (enforced via DynamoDB TTL + runtime checks)
- Single-use: status flips to
usedafter first consumption
StudentTokens: token store (token,student_id,test_case,course_secret,status,created_at,ttl)StudentRateLimit: rate limiting per student (student_id,request_times[],ttl)Classes: course metadata (secret_keyas PK,course_idused to filter)HomeworksTestCases: test case content and librariesGradebook: grade storageHomeworksMetadata: homework metadata (deadline, max submissions, scores)
429from token_generator: back off (≥60s), then retry.- Token errors (
400): regenerate tokens; ensure token matchesstudent_id/test_case_id; ensure not reused; ensure within 1h. - Grader errors: inspect message; could stem from test retrieval, grading exception, or save failure.
- Always transport over HTTPS.
- Do not log tokens or secrets in plaintext.
- Rotate
SYSTEM_SALTand course secrets periodically; regenerating tokens is required after rotation. - Ensure API Gateway keys/authorizers are applied where appropriate.
- Confirm API Gateway paths/hosts and required headers (e.g.,
x-api-key) for each endpoint in production. - Confirm whether
course_namemaps 1:1 tocourse_id(string) inClasses, and whether multiple records percourse_idcan exist. Currently the scan returns the first match. - For
grader, shouldsecretremain optional, or should clients omit it entirely in the new flow? - For
save_student, shouldsecretbe deprecated and ignored when token is present? - Are there size limits for
answerpayloads or preferred serialization beyond base64+dill?
- Acquire
SYSTEM_SALTvia environment (server-side only; clients never see it). - Call
token_generatorbefore each grading attempt. - Pass
token_testandtoken_savetograder(ortokenindividually toget_test_case/save_student). - Handle 429 with backoff; handle 400 by regenerating tokens.
- Respect token TTL (1 hour) and single-use rules.