Verifies the code sent to the user’s email address. This is the second step in the email verification process, confirming the user has access to the provided email.
Endpoint
POST /api/verify/checkCode
Content-Type : application/json
Implementation
#[post( "/verify/checkCode" , format = "application/json" , data = "<code>" )]
pub fn check_code ( code : Json < Code >) -> Json < Response < String >> {
println! ( "Code: {}" , code . code);
println! ( "Code == FAILTHIS: {}" , code . code == "FAILTHIS" );
if code . code == "FAILTHIS" {
Json ( Response {
data : "FAILTHIS" . to_string (),
status : 400 ,
message : "Ungültiger Code" . to_string (),
})
} else {
Json ( Response {
data : "SUCCESS" . to_string (),
status : 200 ,
message : "Code is valid" . to_string (),
})
}
}
This is a simplified implementation for testing. Production code should validate against stored verification codes in the database.
Request
Request Body
The verification code received via email
The email address being verified (used to look up the correct code)
Example Request
{
"code" : "ABC123" ,
"email" : "max.mueller@stud.hs-kempten.de"
}
Request Structure
#[derive( Deserialize )]
pub struct Code {
pub code : String ,
pub email : String ,
}
Response
Response Body
Response data - either “SUCCESS” or “FAILTHIS”
HTTP status code (200 for success, 400 for invalid code)
Human-readable message (may be in German or English)
Response Structure
#[derive( Serialize )]
pub struct Response < T > {
pub data : T ,
pub status : u16 ,
pub message : String ,
}
Response Examples
Success (200)
{
"data" : "SUCCESS" ,
"status" : 200 ,
"message" : "Code is valid"
}
The verification code is valid and the email is now verified.
Error: Invalid Code (400)
{
"data" : "FAILTHIS" ,
"status" : 400 ,
"message" : "Ungültiger Code"
}
The provided code is invalid or has expired.
Error Codes
Code Status Meaning SUCCESS200 Code verified successfully FAILTHIS400 Invalid or expired code
Production Implementation
In production, this endpoint should:
1. Verify Against Database
// Pseudocode for production implementation
let stored_code = sqlx :: query_as :: < _ , CodeEmailPair >(
"SELECT code, email, created_at FROM verification_codes WHERE email = $1"
)
. bind ( & code . email)
. fetch_optional ( & pool )
. await ? ;
let Some ( stored ) = stored_code else {
return Json ( Response {
data : "FAILTHIS" . to_string (),
status : 400 ,
message : "Ungültiger Code" . to_string (),
});
};
if stored . code != code . code {
return Json ( Response {
data : "FAILTHIS" . to_string (),
status : 400 ,
message : "Ungültiger Code" . to_string (),
});
}
2. Check Expiration
let code_age = chrono :: Utc :: now () - stored . created_at;
if code_age . num_minutes () > 15 {
return Json ( Response {
data : "FAILTHIS" . to_string (),
status : 400 ,
message : "Code ist abgelaufen" . to_string (),
});
}
3. Update User Status
// Mark user as verified
sqlx :: query (
"UPDATE users SET email_verified = true, verified_email = $1 WHERE discord_id = $2"
)
. bind ( & code . email)
. bind ( user_id )
. execute ( & pool )
. await ? ;
// Delete used verification code
sqlx :: query ( "DELETE FROM verification_codes WHERE email = $1" )
. bind ( & code . email)
. execute ( & pool )
. await ? ;
Usage Example
JavaScript/Fetch
const verifyCode = async ( code , email ) => {
const response = await fetch ( '/api/verify/checkCode' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({ code , email }),
});
const result = await response . json ();
if ( result . status === 200 ) {
console . log ( 'Email verified successfully!' );
// Redirect to dashboard or show success message
window . location . href = '/admin' ;
} else {
console . error ( result . message );
// Show error to user
alert ( 'Invalid verification code. Please try again.' );
}
};
verifyCode ( 'ABC123' , 'student@stud.hs-kempten.de' );
cURL
curl -X POST https://your-domain.com/api/verify/checkCode \
-H "Content-Type: application/json" \
-d '{
"code": "ABC123",
"email": "max.mueller@stud.hs-kempten.de"
}'
Verification Flow
Security Considerations
Important Security Measures:
Rate Limiting : Limit attempts to 5 per email per hour
Code Expiration : Codes should expire after 15 minutes
Single Use : Delete codes after successful verification
Timing Attacks : Use constant-time comparison for codes
Logging : Log all verification attempts for audit
Rate Limiting Example
// Track failed attempts
let attempts = get_failed_attempts ( & code . email) . await ? ;
if attempts >= 5 {
return Json ( Response {
data : "TOO_MANY_ATTEMPTS" . to_string (),
status : 429 ,
message : "Zu viele Versuche. Bitte warte eine Stunde." . to_string (),
});
}
Code Generation Best Practices
When generating verification codes:
use rand :: Rng ;
// Generate 6-digit numeric code
fn generate_code () -> String {
let mut rng = rand :: thread_rng ();
format! ( "{:06}" , rng . gen_range ( 0 .. 1000000 ))
}
// Or alphanumeric code
fn generate_alphanumeric_code () -> String {
use rand :: distributions :: Alphanumeric ;
rand :: thread_rng ()
. sample_iter ( & Alphanumeric )
. take ( 8 )
. map ( char :: from )
. collect ()
}
Recommendation : Use 6-digit numeric codes for email verification as they’re easy for users to type.
Error Handling
Common Errors
Scenario Response Action Invalid code format 400 FAILTHIS Show error, allow retry Expired code 400 FAILTHIS Offer resend option Email not found 400 FAILTHIS Redirect to sendMail Too many attempts 429 TOO_MANY_ATTEMPTS Enforce cooldown Database error 500 INTERNAL_ERROR Log and show generic error
Testing
The current implementation allows easy testing:
Any code except “FAILTHIS” returns success
“FAILTHIS” returns an error
# Test success
curl -X POST http://localhost:8000/api/verify/checkCode \
-H "Content-Type: application/json" \
-d '{"code": "123456", "email": "test@stud.hs-kempten.de"}'
# Test failure
curl -X POST http://localhost:8000/api/verify/checkCode \
-H "Content-Type: application/json" \
-d '{"code": "FAILTHIS", "email": "test@stud.hs-kempten.de"}'
Send Mail Send verification code to email
Verify Page Email verification page documentation