Build the mental model
This capstone combines four Advanced-chapter lessons: authentication-vs-authorization-deep-dive, token-and-session-security, api-security-beyond-secrets, and website-security-layers-review — merging four separate mental checklists into one production-readiness baseline.
Cybersecurity Basics' projects centered on OWASP Top 10 (SQL injection, XSS) input-handling flaws. This baseline sits one layer up — fixing XSS does not help if authorization is never checked per-resource, letting an attacker read another user's data just by changing an ID in the URL.
- Authentication configured correctly
- Authorization checked per-resource, not just at login
- Tokens never logged, committed, or exposed to client-side code
- API enforces rate limiting
- Secrets in environment variables, not source code
- Dependencies kept up to date
DEVELOPER SECURITY BASELINE
---------------------------
DEVELOPER SECURITY BASELINE
------------------------------
AUTH [PASS/FAIL]
|
v
AUTHZ [PASS/FAIL]
|
v
TOKENS [PASS/FAIL]
|
v
API [PASS/FAIL]
|
v
SECRETS [PASS/FAIL]
|
v
DEPENDENCIES [PASS/FAIL]
|
v
ALL SIX PASS -> PRODUCTION-READY BASELINE METConnect it to a real scenario
Build the baseline as a checklist you can run against any project's configuration. Work through the six categories in a fixed order so nothing gets skipped under deadline pressure.
Authentication
Confirm passwords or passkeys are hashed or handled correctly, and failed-login attempts are rate-limited.
Authorization
Confirm every endpoint that returns or modifies a specific record verifies the requesting user actually owns or is permitted to access that record, not just that they are logged in at all.
Tokens
Search the codebase and logs for tokens appearing in plaintext, confirm none are committed to version control, and confirm none are exposed to client-side JavaScript unnecessarily.
API
Confirm the API enforces rate limiting on sensitive endpoints and that responses return only the fields a client actually needs, not full internal records.
Secrets
Confirm secrets — API keys, database credentials, signing keys — live in environment variables or a secrets manager, never hard-coded in source.
Dependencies
Confirm dependencies are on a maintained update cadence rather than frozen indefinitely.
Never paste real secrets
When you run this checklist against your own project, describe configuration with booleans and short descriptions only — never paste real API keys, tokens, or credentials into this lesson or into any AI tool.
Run the checker function below against a described project's configuration twice: once for a project that fails several categories, and once for a project that passes all six, and compare the two reports side by side.
Try the working example
function checkDeveloperSecurityBaseline(project) {
const checks = [
{
category: "Authentication",
pass: project.auth.passwordsHashedCorrectly && project.auth.loginRateLimited,
detail: "Passwords/passkeys hashed correctly and failed logins are rate-limited",
},
{
category: "Authorization",
pass: project.authz.checkedPerResource,
detail: "Every endpoint verifies the caller owns/may access the specific resource, not just that they are logged in",
},
{
category: "Tokens",
pass: project.tokens.neverLogged && project.tokens.neverCommitted && !project.tokens.exposedToClient,
detail: "Tokens are never logged, never committed to version control, and not needlessly exposed to client-side code",
},
{
category: "API",
pass: project.api.rateLimited && project.api.responsesMinimized,
detail: "Sensitive endpoints are rate-limited and responses return only the fields a client actually needs",
},
{
category: "Secrets",
pass: project.secrets.inEnvVars,
detail: "API keys, DB credentials, and signing keys live in environment variables, not source code",
},
{
category: "Dependencies",
pass: project.dependencies.upToDate,
detail: "Dependencies are on a maintained update cadence, not frozen indefinitely",
},
];
const failed = checks.filter((c) => !c.pass);
return {
project: project.name,
passed: checks.length - failed.length,
total: checks.length,
overallPass: failed.length === 0,
checks: checks.map((c) => ({ category: c.category, status: c.pass ? "PASS" : "FAIL", detail: c.detail })),
};
}
// Described CONFIGURATION only -- booleans, never real keys/tokens/credentials.
const failingProject = {
name: "Example Project A (needs work)",
auth: { passwordsHashedCorrectly: true, loginRateLimited: false },
authz: { checkedPerResource: false },
tokens: { neverLogged: true, neverCommitted: false, exposedToClient: true },
api: { rateLimited: false, responsesMinimized: true },
secrets: { inEnvVars: true },
dependencies: { upToDate: false },
};
const passingProject = {
name: "Example Project B (baseline met)",
auth: { passwordsHashedCorrectly: true, loginRateLimited: true },
authz: { checkedPerResource: true },
tokens: { neverLogged: true, neverCommitted: true, exposedToClient: false },
api: { rateLimited: true, responsesMinimized: true },
secrets: { inEnvVars: true },
dependencies: { upToDate: true },
};
for (const project of [failingProject, passingProject]) {
const report = checkDeveloperSecurityBaseline(project);
console.log(`\n${report.project}: ${report.passed}/${report.total} checks passed, overall ${report.overallPass ? "PASS" : "FAIL"}`);
for (const c of report.checks) {
console.log(` [${c.status}] ${c.category} -- ${c.detail}`);
}
}Project A fails 5 of 6 checks (only Secrets passes) and reports overallPass: false; Project B passes all 6 checks and reports overallPass: true — matching the console output above, which lists PASS/FAIL per category for both projects.5-minute try-it
Describe a real or fictional project of your own across the six boolean categories used in the code (never real production secrets), run checkDeveloperSecurityBaseline on it, and write one concrete remediation step for each FAIL it reports.
One important caution
Treating 'the user is logged in' as equivalent to 'the user is authorized' — authentication and authorization are different checks and both must pass per-resource
Running the baseline once before launch and never again, even though a new endpoint, a new dependency, or a new integration can quietly reopen a category that used to pass
OWASP API Security Top 10 — Digital Privacy & Modern Security