| name | security-patterns |
| description | Zero-trust security patterns for frontend and backend |
| triggers | ["security","auth","authentication","authorization","token","XSS","OWASP"] |
Security Patterns Skill
Enforce zero-trust security across frontend and backend.
When to Use
Automatically activate when:
- Implementing authentication/authorization
- Handling tokens or sessions
- Writing API endpoints
- Storing sensitive data
Zero Trust Principles
Never Trust, Always Verify, Least Privilege
- Every request is authenticated
- Every action is authorized
- Minimal permissions granted
- All data encrypted at rest and in transit
- Complete audit trail
Frontend Security (Angular)
Token Storage — Memory ONLY
@Injectable({ providedIn: 'root' })
export class AuthService {
private accessToken = signal<string | null>(null);
private refreshToken = signal<string | null>(null);
setTokens(access: string, refresh: string) {
this.accessToken.set(access);
this.refreshToken.set(refresh);
}
clearTokens() {
this.accessToken.set(null);
this.refreshToken.set(null);
}
}
localStorage.setItem('token', token);
sessionStorage.setItem('token', token);
XSS Prevention
import { DomSanitizer } from '@angular/platform-browser';
@Component({...})
class SafeComponent {
private sanitizer = inject(DomSanitizer);
trustedHtml = this.sanitizer.bypassSecurityTrustHtml(userContent);
}
[innerHTML]="userContent"
Auto-Logout on Inactivity
@Injectable({ providedIn: 'root' })
export class InactivityService {
private readonly TIMEOUT_MS = 15 * 60 * 1000;
private timeoutId?: number;
resetTimer() {
clearTimeout(this.timeoutId);
this.timeoutId = window.setTimeout(() => this.logout(), this.TIMEOUT_MS);
}
private logout() {
this.authService.clearTokens();
this.router.navigate(['/login']);
}
}
Clear PII on Logout
logout() {
this.accessToken.set(null);
this.refreshToken.set(null);
this.userProfile.set(null);
await this.indexedDb.clear();
if ('serviceWorker' in navigator) {
const caches = await window.caches.keys();
await Promise.all(caches.map(c => window.caches.delete(c)));
}
}
Backend Security (Spring Boot)
Method-Level Authorization
@RestController
@RequestMapping("/api/v1/learners")
@RequiredArgsConstructor
public class LearnerController {
@GetMapping
@PreAuthorize("hasAnyRole('TEACHER', 'ADMIN')")
public List<LearnerResponse> listLearners() { ... }
@PostMapping
@PreAuthorize("hasRole('ADMIN')")
public LearnerResponse createLearner(@Valid @RequestBody request) { ... }
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public void deleteLearner(@PathVariable UUID id) { ... }
}
PII Masking in Responses
public record LearnerResponse(
UUID id,
@JsonSerialize(using = MaskedStringSerializer.class)
String lrn,
String firstName,
@JsonSerialize(using = MaskedStringSerializer.class)
String birthDate
) {}
Audit Logging
@Aspect
@Component
public class AuditAspect {
@Around("@annotation(Auditable)")
public Object audit(ProceedingJoinPoint pjp) throws Throwable {
AuditLog log = AuditLog.builder()
.userId(SecurityContextHolder.getContext().getUserId())
.tenantId(TenantContext.getTenantId())
.action(pjp.getSignature().getName())
.timestamp(Instant.now())
.build();
try {
Object result = pjp.proceed();
log.setStatus("SUCCESS");
return result;
} catch (Exception e) {
log.setStatus("FAILURE");
log.setError(e.getMessage());
throw e;
} finally {
auditRepository.save(log);
}
}
}
Input Validation
public record CreateLearnerRequest(
@NotBlank
@Size(max = 100)
@Pattern(regexp = "^[a-zA-Z\\s]+$", message = "Only letters allowed")
String firstName,
@NotNull
@Pattern(regexp = "\\d{12}", message = "LRN must be 12 digits")
String lrn,
@NotNull
@Past(message = "Birth date must be in the past")
LocalDate birthDate
) {}
API Security
OAuth2 + PKCE Flow
1. Client generates code_verifier (random string)
2. Client creates code_challenge = SHA256(code_verifier)
3. Client redirects to /authorize?code_challenge=...
4. User authenticates
5. Server returns authorization_code
6. Client exchanges code + code_verifier for tokens
7. Server validates SHA256(code_verifier) == code_challenge
Rate Limiting
@Configuration
public class RateLimitConfig {
@Bean
public RateLimiter rateLimiter() {
return RateLimiter.of("api", RateLimiterConfig.custom()
.limitForPeriod(100)
.limitRefreshPeriod(Duration.ofMinutes(1))
.timeoutDuration(Duration.ofMillis(500))
.build());
}
}
Data Encryption
At Rest (Database)
CREATE TABLE learners (
id UUID PRIMARY KEY,
lrn TEXT,
first_name TEXT,
birth_date DATE
);
INSERT INTO learners (id, lrn, first_name, birth_date)
VALUES (
gen_random_uuid(),
pgp_sym_encrypt('123456789012', 'encryption-key'),
'Juan',
'2010-01-15'
);
In Transit
- TLS 1.3 for all connections
- mTLS between services
- Certificate pinning in mobile apps
Security Headers (CSP)
@Configuration
public class SecurityHeadersConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
return http
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'; script-src 'self'"))
.frameOptions(frame -> frame.deny())
.xssProtection(xss -> xss.enable()))
.build();
}
}
Checklist
Frontend
Backend
Infrastructure