verify
In software, verification is the process of testing whether a claim can be trusted. The claim may be that an identity is genuine, a file has not been changed, a token was issued by an authorized party, or an operation produced the expected result.
A verification mechanism typically relies on established rules, cryptographic keys, digital signatures, checksums, or assertions. Its central question is simple: “Is this true, and can we prove it?”
Verification should happen before untrusted data or an unverified identity is allowed to influence later operations. A failed check should stop the workflow rather than silently pass questionable information downstream.
Verification and Validation Are Different
Although the two concepts are often used interchangeably, they address different questions.
| Concept | Core question | Example |
|---|---|---|
| Validation | “Does this input satisfy the required rules?” | Is the email address formatted correctly? Is the password long enough? |
| Verification | “Is this claim authentic or correct?” | Does the submitted password match the stored hash? Was this token signed by the expected issuer? |
| Authorization | “Is this identity allowed to perform this action?” | May this user edit the record? |
Validation usually examines shape, type, length, range, and format. Verification examines authenticity, integrity, consistency, and provenance. In practice, both are often required. A system might first validate that an account number contains ten digits, then verify that it matches a trusted account record.
Common Forms of Verification
- Input validation ensures that user-provided values meet explicit constraints, such as a valid date range or an allowed file type.
- Identity verification confirms that a person, device, or service is who it claims to be. Password checks, passkeys, OAuth callbacks, and certificate validation fall into this category.
- Integrity verification detects unauthorized changes to data. SHA-256 checksums, HMAC signatures, and file digests are common tools.
- Signature and certificate verification checks whether a signature is valid, a certificate chain is trustworthy, and a certificate has not expired or been revoked.
- Token verification validates the signature and registered claims of a token, including its issuer, audience, expiration time, and subject.
- Test verification uses assertions to confirm that actual behavior matches an expected outcome.
These checks answer different trust questions. Passing one does not automatically imply that the others have passed.
A Defensible Verification Process
A reliable implementation follows a deliberate sequence:
- Define the claim. Identify exactly what must be proven: an identity, a file digest, a token signature, a specific test result, or another property.
- Use trusted sources. Verification is only as strong as the keys, expected values, policy data, and public certificates used to perform it.
- Validate before interpreting. Confirm basic types and formats before applying complex rules or cryptographic operations.
- Apply explicit rules. Prefer allowlists and well-defined constraints over vague pattern matching.
- Check relevant properties in order. For a token, this may mean signature, issuer, audience, expiration, and subject. For a signed request, also check that the payload has not been altered.
- Fail closed. Reject the operation when required evidence is missing, invalid, or unavailable.
- Record useful evidence. Audit failures without exposing passwords, private keys, session tokens, or other sensitive values.
Verification results may be returned as booleans or raised as exceptions. Boolean results work well for simple predicates, while exceptions can make sense when invalid evidence must interrupt a larger workflow. Whichever style is chosen, failure should never be mistaken for success.
Verifying a File Digest
The following Python function calculates a file’s SHA-256 digest and compares it with a trusted expected digest. hmac.compare_digest performs a constant-time comparison, reducing the risk of timing-based information leaks.
import hashlib
import hmac
from pathlib import Path
def verify_sha256(file_path: str, expected_hex: str) -> bool:
digest = hashlib.sha256()
with Path(file_path).open("rb") as file:
for chunk in iter(lambda: file.read(64 * 1024), b""):
digest.update(chunk)
expected = bytes.fromhex(expected_hex)
return hmac.compare_digest(digest.digest(), expected)
This pattern is useful for downloaded packages, backups, build artifacts, and software distributions. However, a checksum only proves that the file matches the expected digest. If that digest came from the same untrusted source as the file, an attacker could replace both. The expected digest must therefore come from a trusted channel.
Verifying a JWT
JSON Web Token verification requires more than decoding the payload. A production implementation must validate the signature and relevant claims. The following example uses PyJWT:
import jwt
from jwt import InvalidTokenError
class TokenVerificationError(Exception):
pass
def verify_access_token(
token: str,
secret: str,
) -> dict:
try:
payload = jwt.decode(
token,
secret,
algorithms=["HS256"],
issuer="auth.example.com",
audience="api.example.com",
options={
"require": ["exp", "iat", "sub", "iss", "aud"]
},
)
return payload
except InvalidTokenError:
raise TokenVerificationError(
"The access token could not be verified."
) from None
Pinning algorithms=["HS256"] is important. Accepting whatever algorithm appears in the token header can open the door to algorithm-confusion attacks. The secret used with HMAC-based algorithms should also have sufficient strength and should be rotated through a controlled process.
In many production environments, asymmetric algorithms such as RS256 or ES256 are preferable because verification services need only the public key. Key rotation, revocation, and cache invalidation must still be designed as part of the verification strategy.
Secure Failure Handling
Verification failures should be handled carefully:
- Return a generic external error when detailed failure reasons could help an attacker. “Token verification failed” is usually safer than revealing whether the token was expired, malformed, or signed by the wrong issuer.
- Preserve detailed diagnostics in protected internal logs when troubleshooting requires them.
- Never log passwords, raw session tokens, private keys, or complete authorization headers.
- Apply rate limits to repeated failures and alert on unusual patterns.
- Distinguish malformed input from a valid but unauthorized identity without revealing sensitive account information.
- Avoid fallback paths that continue processing after verification fails.
An error message does not need to be vague internally. The key is to separate operational diagnostics from information exposed to untrusted callers.
Verification in Automated Tests
Testing is another form of verification: it compares observed behavior with a declared expectation. A useful test suite covers more than successful cases.
For a verification function, relevant scenarios include:
- Valid data that should pass
- Missing or malformed inputs
- Boundary values
- Expired or not-yet-valid tokens
- Incorrect signatures, issuers, or audiences
- Modified payloads
- Unexpected algorithms
- Rotated or unavailable keys
- Large files and interrupted reads
- Concurrent requests and repeated failures
Mocking time can make expiration behavior deterministic. Tests should assert both the final outcome and the reason for rejection when that distinction matters.
Practical Principles
- Perform security checks on the server. Client-side checks improve usability but cannot protect server-side assets.
- Keep rules explicit. Centralized, testable policies are easier to audit and maintain.
- Use constant-time comparisons for secrets. Functions such as
hmac.compare_digesthelp prevent timing attacks. - Verify freshness and context. A valid signature does not prove that a token is current or intended for the current service.
- Treat key material as sensitive. Store secrets in dedicated secret-management systems and define access and rotation policies.
- Minimize exposed information. Both successful and failed checks should reveal only what the caller needs to know.
- Combine validation, verification, and authorization. Each protects a different part of the trust boundary.
Conclusion
Verification adds evidence to a system’s decisions. It is used to establish identity, protect data integrity, validate cryptographic material, and confirm expected behavior. The distinction between validation and verification is crucial: validation asks whether data is acceptable, while verification asks whether a claim is trustworthy.
Strong verification systems rely on explicit rules, trusted sources, cryptographic checks, fail-closed behavior, careful error handling, and comprehensive tests. When these principles are applied consistently, they prevent untrusted information from advancing through the system and make software behavior more secure, predictable, and dependable.