Loading...
Loading...
Review code for Government of Canada authentication and identity management compliance. Checks OIDC implementations, session security, scope minimization, logout handling, and RBAC integration against ITSG-33 and TBS security standards.
npx skill4agent add dougkeefe/gc-code-skills gc-review-iamlogin.microsoftonline.comclegc-gckey.gc.ca# Node.js
ls package.json 2>/dev/null && cat package.json | head -50
# Python
ls requirements.txt setup.py pyproject.toml 2>/dev/null
# .NET
ls *.csproj *.sln 2>/dev/null
# Java
ls pom.xml build.gradle 2>/dev/null
# Go
ls go.mod 2>/dev/null| Stack | Common Auth Libraries |
|---|---|
| Node.js | passport, express-session, next-auth, @auth/core, msal-node |
| Python | flask-login, django-allauth, authlib, msal |
| .NET | Microsoft.Identity.Web, IdentityServer |
| Java | spring-security-oauth2, keycloak |
| Go | coreos/go-oidc, golang.org/x/oauth2 |
# Find auth-related directories and files
find . -type f \( \
-path "*/auth/*" -o \
-path "*/authentication/*" -o \
-path "*/identity/*" -o \
-path "*/login/*" -o \
-path "*/session/*" -o \
-path "*/middleware/*" -o \
-name "*auth*" -o \
-name "*identity*" -o \
-name "*oidc*" -o \
-name "*oauth*" -o \
-name "*session*" -o \
-name "*login*" \
\) -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/vendor/*" 2>/dev/null# Find files containing auth-related code
grep -rl --include="*.ts" --include="*.js" --include="*.py" --include="*.cs" --include="*.java" --include="*.go" \
-e "passport\|next-auth\|msal\|@azure/identity" \
-e "openid\|oidc\|oauth" \
-e "clientId\|clientSecret\|client_id\|client_secret" \
-e "httpOnly\|HttpOnly\|SameSite" \
-e "GCKey\|Entra\|AzureAD" \
. 2>/dev/null | grep -v node_modules | grep -v vendor# Config files that may contain auth settings
find . -type f \( \
-name "*.env*" -o \
-name "appsettings*.json" -o \
-name "config*.json" -o \
-name "config*.yaml" -o \
-name "config*.yml" \
\) -not -path "*/node_modules/*" 2>/dev/nullissuer|authority|identityProvider|authorizationUrl|tokenUrllogin.microsoftonline.comclegc-gckey.gc.caaccounts.google.com| Status | File | Issue Found | Recommended Action |
| ❌ **Fail** | {file}:{line} | [Auth Error] Unauthorized identity provider: {provider} | Use Entra ID or GCKey as per TBS guidelines |clientSecret\s*[:=]\s*["'][^"']{8,}["']
client_secret\s*[:=]\s*["'][^"']{8,}["']
AZURE_CLIENT_SECRET\s*[:=]\s*["'][^"']{8,}["']
secret\s*[:=]\s*["'][A-Za-z0-9+/=]{20,}["']process.envos.environEnvironment.GetEnvironmentVariable.env.example| ❌ **Fail** | {file}:{line} | [Auth Error] Hardcoded client secret detected | Move to environment variable or Azure Key Vault. Rotate the exposed secret immediately. |.well-known/openid-configurationauthorization_endpoint|token_endpoint|userinfo_endpoint|jwks_uri/.well-known/openid-configurationauthorization_endpointtoken_endpoint| ⚠️ **Warning** | {file}:{line} | Hardcoded OIDC endpoint instead of using discovery | Use wellKnown endpoint for automatic configuration |// Check express-session or cookie config
cookie: {
httpOnly: true, // MUST be true
secure: true, // MUST be true in production
sameSite: 'strict' // MUST be 'strict' or 'lax'
}SESSION_COOKIE_HTTPONLY = True # MUST be True
SESSION_COOKIE_SECURE = True # MUST be True
SESSION_COOKIE_SAMESITE = 'Strict' # MUST be 'Strict' or 'Lax'SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = 'Strict'
CSRF_COOKIE_SECURE = Trueoptions.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;HttpOnly = trueSecure = trueSameSite = StrictLaxfalseSameSite = NoneSecure = true| ❌ **Fail** | {file}:{line} | [Auth Error] Cookie {flag} flag is {value} | Set {flag}: true (required for Protected B data) |maxAge|max_age|expires|expiresIn|timeout|ttl|lifetime|PERMANENT_SESSION_LIFETIME| ⚠️ **Warning** | {file}:{line} | Session timeout set to {value} (exceeds 8-hour limit) | Reduce to 28800 seconds or less per ITSG-33 || ❌ **Fail** | {file}:{line} | [Auth Error] Tokens stored in localStorage | Use httpOnly cookies or server-side session storage |scope[s]?\s*[:=]\s*["'][^"']*["']openidprofileemailoffline_accessUser.ReadWrite.AllDirectory.Read.All| ⚠️ **Warning** | {file}:{line} | Requesting '{scope}' scope but usage not detected | Reduce scopes to minimum required (Privacy Act compliance) |jwt_decode|jwtDecode|atob.*split|parseJwt|decodeToken| ❌ **Fail** | {file}:{line} | [Auth Error] JWT decoded in frontend code | Move token processing to backend API |req.session.destroy() // Session destruction
req.logout() // Passport logout
res.clearCookie() // Cookie clearingsession.clear() # Flask session
logout_user() # Flask-LoginHttpContext.SignOutAsync()| ⚠️ **Warning** | {file}:{line} | Logout only clears cookie, session may persist | Add explicit session.destroy() or equivalent |end_session_endpoint|logout.*redirect|signOut.*redirect|post_logout_redirectend_session_endpointpost_logout_redirect_uriend_session_endpoint| ⚠️ **Warning** | {file}:{line} | Missing OIDC End Session endpoint call | Implement federated logout via end_session_endpoint |roles|groups|claims.*role|hasRole|isInRole|authorize|@Roles|[Authorize]| ❌ **Fail** | {file}:{line} | [Auth Error] Role authorization in frontend code | Move role checks to backend middleware |req\.body\.role|request\.role|role.*header|x-user-role| ❌ **Fail** | {file}:{line} | [Auth Error] Roles read from client request | Source roles only from validated IdP token |================================================================================
Government of Canada - Identity & Authentication Review
Skill ID: GOC-AUTH-001
================================================================================
Project: {project name from package.json or directory}
Files Reviewed: {count}
Review Date: {current date}
Technology Stack: {detected framework}
Standards Applied:
- ITSG-33 (Identification and Authentication)
- TBS Standard on Security Tabs
- TBS Guideline on Defining Authentication Requirements
- Privacy Act (Scope Minimization)
--------------------------------------------------------------------------------REVIEW SUMMARY
==============
| Category | Status | Issues |
|----------|--------|--------|
| A. OIDC Implementation | {PASS/FAIL/WARN} | {count} |
| B. Session Security | {PASS/FAIL/WARN} | {count} |
| C. Scope Minimization | {PASS/FAIL/WARN} | {count} |
| D. Logout Handling | {PASS/FAIL/WARN} | {count} |
| E. RBAC Integration | {PASS/FAIL/WARN} | {count} |
Total: {X} Failures, {Y} Warnings, {Z} PassesDETAILED FINDINGS
=================
| Status | File | Issue Found | Recommended Action |
|--------|------|-------------|-------------------|
| ❌ **Fail** | src/auth/config.ts:15 | [Auth Error] Hardcoded client secret | Move to environment variable or Key Vault |
| ❌ **Fail** | src/pages/login.tsx:42 | [Auth Error] JWT decoded in frontend | Move token processing to backend API |
| ⚠️ **Warning** | src/session.ts:8 | Session timeout exceeds 8 hours | Reduce to 28800 seconds or less |
| ⚠️ **Warning** | src/auth/scopes.ts:12 | Requesting 'offline_access' scope | Verify business justification for refresh tokens |
| ✅ **Pass** | src/middleware/auth.ts | RBAC implemented server-side | None |
| ✅ **Pass** | src/auth/oidc.ts | Using Entra ID with wellKnown endpoint | None |--------------------------------------------------------------------------------
[Auth Error] Hardcoded Client Secret
--------------------------------------------------------------------------------
File: src/auth/config.ts:15
Category: A. OIDC Implementation Standards
Severity: FAIL
Reference: ITSG-33 IA-5 (Authenticator Management)
Code Found:
┌─────────────────────────────────────────────────────────────
│ const config = {
│ clientId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
│ clientSecret: 'abc123secret456xyz' // <-- VIOLATION
│ };
└─────────────────────────────────────────────────────────────
Issue:
Client secrets must never be stored in source code. This violates
ITSG-33 IA-5 (Authenticator Management) and TBS Standard on Security
Tabs. Exposed secrets can lead to unauthorized access to the identity
provider and impersonation attacks.
Recommended Action:
1. Remove the secret from source code immediately
2. Store in environment variable:
- process.env.AZURE_CLIENT_SECRET (Node.js)
- os.environ['AZURE_CLIENT_SECRET'] (Python)
3. For production: Use Azure Key Vault or equivalent secrets manager
4. CRITICAL: Rotate the exposed secret in Entra ID immediately
Remediation Example:
┌─────────────────────────────────────────────────────────────
│ const config = {
│ clientId: process.env.AZURE_CLIENT_ID,
│ clientSecret: process.env.AZURE_CLIENT_SECRET
│ };
└─────────────────────────────────────────────────────────────
--------------------------------------------------------------------------------================================================================================
COMPLIANCE SUMMARY
================================================================================
{If any FAIL}:
⛔ This codebase has CRITICAL authentication compliance issues that must
be resolved before deployment. Address all [Auth Error] findings.
{If only WARN}:
⚠️ This codebase has authentication warnings that should be reviewed.
Consider addressing warnings to improve security posture.
{If all PASS}:
✅ This codebase passes all Government of Canada authentication
compliance checks. Continue to monitor for changes.
--------------------------------------------------------------------------------
Next Steps:
1. Address all ❌ Fail findings before proceeding
2. Review ⚠️ Warning findings with your security team
3. Re-run /gc-review-iam after fixes are applied
4. Document any accepted risks with justification
For questions about GoC authentication standards, consult:
- CCCS Cyber Centre: https://cyber.gc.ca
- TBS Digital Standards: https://www.canada.ca/en/government/system/digital-government
================================================================================// express-session
app.use(session({
secret: process.env.SESSION_SECRET, // Not hardcoded
cookie: {
httpOnly: true, // Required
secure: true, // Required for HTTPS
sameSite: 'strict', // Required
maxAge: 28800000 // 8 hours max
},
resave: false,
saveUninitialized: false
}));// passport-azure-ad or passport-openidconnect
passport.use(new OIDCStrategy({
identityMetadata: 'https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration',
clientID: process.env.AZURE_CLIENT_ID,
clientSecret: process.env.AZURE_CLIENT_SECRET, // From env
responseType: 'code',
scope: ['openid', 'profile', 'email'] // Minimal scopes
}));// app/api/auth/[...nextauth]/route.js or auth.config.js
export const authOptions = {
providers: [
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID
})
],
session: {
strategy: 'jwt',
maxAge: 28800 // 8 hours
},
cookies: {
sessionToken: {
options: {
httpOnly: true,
sameSite: 'lax',
secure: true
}
}
}
};# config.py or app.py
app.config.update(
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_SAMESITE='Strict',
PERMANENT_SESSION_LIFETIME=timedelta(hours=8),
SECRET_KEY=os.environ.get('SECRET_KEY') # From env
)# OIDC client configuration
oauth = OAuth(app)
oauth.register(
name='azure',
client_id=os.environ.get('AZURE_CLIENT_ID'),
client_secret=os.environ.get('AZURE_CLIENT_SECRET'),
server_metadata_url='https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration',
client_kwargs={'scope': 'openid profile email'}
)// Program.cs or Startup.cs
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.Configure<CookieAuthenticationOptions>(
CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.ExpireTimeSpan = TimeSpan.FromHours(8);
});{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "from-env-or-keyvault",
"ClientId": "from-env-or-keyvault",
"ClientSecret": "NEVER-IN-CONFIG-FILE"
}
}| Check | ITSG-33 Control | Description |
|---|---|---|
| 3.1 Authorized IdP | IA-2, IA-8 | Identification and Authentication (Organizational Users, Non-Organizational Users) |
| 3.2 No Hardcoded Secrets | IA-5 | Authenticator Management |
| 3.3 Discovery Endpoint | SC-8, SC-23 | Transmission Confidentiality, Session Authenticity |
| 4.1 Cookie Flags | SC-8, SC-23 | Transmission Confidentiality, Session Authenticity |
| 4.2 Session Timeout | AC-12, SC-10 | Session Termination, Network Disconnect |
| 4.3 Token Storage | SC-28 | Protection of Information at Rest |
| 5.1 Scope Minimization | AC-6 | Least Privilege |
| 5.2 Server-side Claims | AC-4, SC-8 | Information Flow, Transmission Confidentiality |
| 6.1 Session Clearing | AC-12 | Session Termination |
| 6.2 Federated Logout | AC-12, IA-4 | Session Termination, Identifier Management |
| 7.1 Server-side RBAC | AC-3, AC-6 | Access Enforcement, Least Privilege |
| 7.2 Role Integrity | AC-3, SI-10 | Access Enforcement, Information Input Validation |
# Run authentication review on current project
/gc-review-iam
# Review specific files
/gc-review-iam src/auth/**
# Review with strict mode (warnings become failures)
/gc-review-iam --strict