Evaly provides comprehensive access control features to ensure only authorized participants can take your tests. Combine multiple layers of security to protect your assessments.
Access Modes
Public Access
Anyone with the test link can participate:
Public tests can still have additional restrictions like password protection or email domain filtering.
Private Access
Only invited participants can access the test:
When a test is set to private, participants must be on the allowlist (individual emails or groups) to access it.
Access Restriction Methods
Password Protection
Require a password to access the test:
Set Password
await updateAccessSettings ({
testId ,
password: "SecurePass123"
});
Participant Verification
Participants must enter the password before starting the test. The password is validated on the server and stored in their test session.
Remove Password
await updateAccessSettings ({
testId ,
password: null // Clears password
});
Email Domain Restrictions
Limit access to specific email domains (e.g., company or university domains):
await updateAccessSettings ({
testId ,
allowedEmailDomains: [ "company.com" , "university.edu" ]
});
How it works:
Participant email is checked against the allowed domains list
Subdomains are supported (e.g., “mit.edu” allows “student.mit.edu”)
Case-insensitive matching
Example: University Domain Filtering
// Only allow university emails
await updateAccessSettings ({
testId ,
allowedEmailDomains: [
"stanford.edu" ,
"mit.edu" ,
"harvard.edu"
]
});
Valid: [email protected] , [email protected] Invalid: [email protected] , [email protected]
IP Address Whitelisting
Restrict test access to specific IP addresses or ranges:
await updateAccessSettings ({
testId ,
allowedIpAddresses: [
"192.168.1.100" ,
"10.0.0.0/24"
]
});
Use cases:
Campus-only testing (restrict to university network)
Office-only assessments
Proctored testing centers
Participant Management
Individual Participants
Add specific participants by email:
Add Single Participant
Email validation is performed server-side using regex pattern: / ^ [ ^ \s@ ] + @ [ ^ \s@ ] + \. [ ^ \s@ ] + $ /
Bulk Add Participants
Returns results array: [
{ email: "student1@..." , success: true , id: "abc123" },
{ email: "student2@..." , success: false , error: "Already exists" },
{ email: "invalid" , success: false , error: "Invalid email format" }
]
Remove Participant
await removeParticipant ({
participantId: "jh7..."
});
Performs soft delete by setting deletedAt timestamp.
Participant Groups
Manage access for groups of users:
Create User Group
First, create a user group in your organization: // Groups are managed separately
const groupId = await createUserGroup ({
name: "Spring 2025 Students" ,
organizationId
});
Add Members to Group
Populate the group with members:
Assign Group to Test
await addParticipantGroup ({
testId ,
userGroupId: groupId
});
Group must belong to the same organization as the test.
Remove Group Assignment
await removeParticipantGroup ({
participantGroupId
});
Querying Access Settings
Retrieve current access configuration:
const settings = await getAccessSettings ({ testId });
// Returns:
{
access : "public" | "private" ,
password ?: string ,
allowedEmailDomains : string [],
allowedIpAddresses : string [],
scheduledStartAt ?: number ,
scheduledEndAt ?: number
}
Database Schema
Test Participants
// testParticipant table
{
testId : Id < "test" > ,
email : string ,
addedAt : number ,
deletedAt ?: number // Soft delete
}
// Indexes:
// - by_test_id
// - by_email
// - by_test_id_email (for uniqueness checks)
Participant Groups
// testParticipantGroup table
{
testId : Id < "test" > ,
userGroupId : Id < "userGroup" > ,
addedAt : number ,
deletedAt ?: number
}
// Indexes:
// - by_test_id
// - by_user_group_id
Access Validation Flow
When a participant attempts to access a test:
Check Test Status
Is test published?
Is test within scheduled time window?
Has test finished?
Check Access Mode
If private: Is participant on allowlist (individual or group)?
Check Password
If password is set: Does participant provide correct password?
Check Email Domain
If domains are restricted: Does participant’s email match allowed domains?
Check IP Address
If IP whitelist exists: Does participant’s IP match allowed addresses?
Grant Access
Create test session
Allow participant to start
Combining Restrictions
You can layer multiple access controls:
// Secure university final exam
await updateAccessSettings ({
testId ,
access: "private" , // Require allowlist
password: "FinalExam2025" , // Require password
allowedEmailDomains: [ "university.edu" ], // University emails only
allowedIpAddresses: [ "10.50.0.0/16" ], // Campus network only
scheduledStartAt: examStartTime , // Available during exam window
scheduledEndAt: examEndTime
});
// Add enrolled students
await addParticipantGroup ({
testId ,
userGroupId: "CS101_Students"
});
Schedule Integration
Access settings include scheduling fields:
await updateAccessSettings ({
testId ,
scheduledStartAt: 1735689600000 ,
scheduledEndAt: 1735693200000
});
Schedule Validation: When using section-based durations, the system validates that total section duration fits within the test window: if ( totalSectionDuration > testWindowMinutes ) {
throw new ConvexError ({
message: `Cannot update schedule: \n\n Total section duration: ${ totalSectionDuration } min \n Test window: ${ testWindowMinutes } min`
});
}
Soft Delete Pattern
Participants and groups use soft deletion:
// Delete
await ctx . db . patch ( participantId , {
deletedAt: Date . now ()
});
// Restore (when re-adding)
if ( existing . deletedAt && existing . deletedAt > 0 ) {
await ctx . db . patch ( existing . _id , {
deletedAt: undefined ,
addedAt: Date . now ()
});
}
// Query (exclude deleted)
. filter (( q ) => q . lte ( q . field ( "deletedAt" ), 0 ))
Best Practices
Use private mode for sensitive or graded assessments
Set password protection for public tests shared via link
Restrict email domains to prevent unauthorized access from external users
Combine with scheduling to limit when tests are accessible
Use groups for recurring classes or cohorts instead of managing individual emails
Test access controls before the actual exam to ensure participants can enter
Document password distribution method to participants (email, LMS, etc.)