Skip to main content
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

src/web/api/mod.rs
#[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

code
string
required
The verification code received via email
email
string
required
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

src/web/structs.rs
#[derive(Deserialize)]
pub struct Code {
    pub code: String,
    pub email: String,
}

Response

Response Body

data
string
Response data - either “SUCCESS” or “FAILTHIS”
status
number
HTTP status code (200 for success, 400 for invalid code)
message
string
Human-readable message (may be in German or English)

Response Structure

src/web/structs.rs
#[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

CodeStatusMeaning
SUCCESS200Code verified successfully
FAILTHIS400Invalid 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:
  1. Rate Limiting: Limit attempts to 5 per email per hour
  2. Code Expiration: Codes should expire after 15 minutes
  3. Single Use: Delete codes after successful verification
  4. Timing Attacks: Use constant-time comparison for codes
  5. 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

ScenarioResponseAction
Invalid code format400 FAILTHISShow error, allow retry
Expired code400 FAILTHISOffer resend option
Email not found400 FAILTHISRedirect to sendMail
Too many attempts429 TOO_MANY_ATTEMPTSEnforce cooldown
Database error500 INTERNAL_ERRORLog 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

Build docs developers (and LLMs) love