Jakarta Security Interview Questions and Answers
Master Jakarta Security with production-ready interview questions covering authentication, authorization, IdentityStore, HttpAuthenticationMechanism, SecurityContext, role-based access control, JWT integration, REST API security, password handling, and senior-level best practices.
Jakarta Security Interview Questions and Answers
Introduction
Jakarta Security provides a standard security programming model for Jakarta EE applications.
It helps applications implement common security requirements such as:
- User authentication
- Role-based authorization
- Identity validation
- Credential validation
- Security-context access
- Form-based login
- Basic authentication
- Custom authentication mechanisms
- Integration with REST resources
- Declarative access control
Jakarta Security works together with other Jakarta EE technologies, including:
- Jakarta REST
- Jakarta Servlet
- Jakarta CDI
- Jakarta Persistence
- Jakarta Bean Validation
- Jakarta Transactions
A production-ready security design must consider much more than checking a username and password.
It must also address:
- Password hashing
- Credential storage
- Session security
- Token validation
- Role mapping
- Resource ownership
- Multi-factor authentication
- Secure cookies
- CSRF protection
- CORS
- Rate limiting
- Audit logging
- Error handling
- Secret management
- Token expiration
- Revocation
- Least privilege
- Defense in depth
Authentication answers:
Who is the caller?
Authorization answers:
What is the caller allowed to do?
A secure enterprise application must implement both correctly.
This guide covers the 15 most frequently asked Jakarta Security interview questions with code examples, Mermaid diagrams, production scenarios, common mistakes, and senior-level recommendations.
Q1. What is Jakarta Security?
Answer
Jakarta Security is the Jakarta EE specification that standardizes application-level authentication and identity-store integration.
It provides APIs and annotations for:
- Authentication mechanisms
- Credential validation
- Identity stores
- Security context access
- Role checks
- Login status handling
- Container integration
Jakarta Security allows applications to define security behavior using standard Jakarta EE APIs rather than relying entirely on application-server-specific configuration.
Main Components
HttpAuthenticationMechanismIdentityStoreIdentityStoreHandlerSecurityContextCredentialAuthenticationStatusAuthenticationParameters- Security annotations
High-Level Architecture
flowchart TD
A[Client Request] --> B[Jakarta EE Container]
B --> C[HTTP Authentication Mechanism]
C --> D[Identity Store Handler]
D --> E[Identity Store]
E --> F[User Credentials and Groups]
F --> G[Authenticated Principal]
G --> H[Security Context]
H --> I[Authorization Check]
I --> J[Protected Resource]
Why Interviewers Ask This
Interviewers want to know whether you understand Jakarta Security as a standard container-integrated security model rather than a standalone authentication server.
Production Example
A customer portal may use Jakarta Security to authenticate users against a database-backed identity store and then protect REST endpoints with role checks.
Common Mistake
Describing Jakarta Security as a complete OAuth 2.0 or OpenID Connect provider.
Senior Follow-up
Jakarta Security handles application authentication and identity validation, but external identity federation is commonly delegated to a dedicated identity provider.
Q2. What is the difference between authentication and authorization?
Answer
Authentication verifies the identity of the caller.
Authorization determines whether the authenticated caller has permission to perform an action.
Authentication Examples
- Username and password
- Client certificate
- One-time password
- JWT token
- Session cookie
- API key
- External identity-provider login
Authorization Examples
- Only administrators can delete users.
- Customers can access only their own accounts.
- Claims adjusters can approve claims below a limit.
- Managers can view department reports.
- Service accounts can call specific APIs.
Security Flow
flowchart TD
A[Incoming Request] --> B{Authenticated?}
B -->|No| C[Authenticate Caller]
C --> D{Authentication Successful?}
D -->|No| E[Return 401 Unauthorized]
D -->|Yes| F[Create Security Identity]
B -->|Yes| F
F --> G{Authorized for Resource?}
G -->|No| H[Return 403 Forbidden]
G -->|Yes| I[Execute Protected Operation]
Comparison
| Authentication | Authorization |
|---|---|
| Confirms identity | Confirms permission |
| Happens first | Happens after authentication |
| Uses credentials | Uses roles, permissions, ownership, or policy |
| Failure commonly returns 401 | Failure commonly returns 403 |
| Example: login | Example: access admin endpoint |
Example
if (!securityContext.getCallerPrincipal()
.getName()
.equals(accountOwner)) {
throw new ForbiddenException();
}
Common Mistake
Using authentication as proof that a caller may access every authenticated resource.
Senior Follow-up
Role checks are often insufficient by themselves. Fine-grained resource ownership and business policy checks may also be required.
Q3. What is an IdentityStore?
Answer
An IdentityStore validates caller credentials and returns identity information such as groups or roles.
It can validate credentials against:
- A relational database
- LDAP
- An external directory
- A custom user store
- An enterprise identity system
Basic Interface Role
An identity store typically performs one or both operations:
- Credential validation
- Group retrieval
Database Identity Store Concept
flowchart LR
A[Authentication Mechanism] --> B[IdentityStoreHandler]
B --> C[Database IdentityStore]
C --> D[User Table]
C --> E[Role or Group Table]
Custom Identity Store Example
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.security.enterprise.credential.UsernamePasswordCredential;
import jakarta.security.enterprise.identitystore.CredentialValidationResult;
import jakarta.security.enterprise.identitystore.IdentityStore;
import java.util.Set;
@ApplicationScoped
public class ApplicationIdentityStore
implements IdentityStore {
private final UserRepository userRepository;
private final PasswordService passwordService;
public ApplicationIdentityStore(
UserRepository userRepository,
PasswordService passwordService
) {
this.userRepository = userRepository;
this.passwordService = passwordService;
}
@Override
public CredentialValidationResult validate(
UsernamePasswordCredential credential
) {
return userRepository
.findByUsername(
credential.getCaller()
)
.filter(UserAccount::isActive)
.filter(
user -> passwordService.matches(
credential.getPasswordAsString(),
user.getPasswordHash()
)
)
.map(
user ->
new CredentialValidationResult(
user.getUsername(),
user.getRoles()
)
)
.orElse(
CredentialValidationResult.INVALID_RESULT
);
}
@Override
public Set<ValidationType>
validationTypes() {
return Set.of(
ValidationType.VALIDATE
);
}
}
Validation Result
A successful result may contain:
- Caller name
- Principal
- Groups
- Distinguished name
- Unique identifier
Common Mistake
Returning raw database roles without validating whether the user account is active, locked, or expired.
Senior Follow-up
Identity validation should also consider account status, credential expiration, lockout, tenant context, and security audit requirements.
Q4. What is IdentityStoreHandler?
Answer
IdentityStoreHandler coordinates one or more identity stores.
An authentication mechanism can pass credentials to the handler instead of calling a specific identity store directly.
Architecture
flowchart TD
A[Authentication Mechanism] --> B[IdentityStoreHandler]
B --> C[Database IdentityStore]
B --> D[LDAP IdentityStore]
B --> E[Custom IdentityStore]
C --> F[Credential Result]
D --> F
E --> F
F --> G[Combined Caller Identity]
Example
import jakarta.inject.Inject;
import jakarta.security.enterprise.identitystore.IdentityStoreHandler;
@ApplicationScoped
public class CredentialService {
private final IdentityStoreHandler
identityStoreHandler;
@Inject
public CredentialService(
IdentityStoreHandler identityStoreHandler
) {
this.identityStoreHandler =
identityStoreHandler;
}
public CredentialValidationResult validate(
UsernamePasswordCredential credential
) {
return identityStoreHandler.validate(
credential
);
}
}
Benefits
- Decouples authentication mechanism from storage
- Supports multiple stores
- Centralizes validation coordination
- Allows group aggregation
- Supports standard container behavior
Common Mistake
Hardcoding database-access logic directly inside the HTTP authentication mechanism.
Senior Follow-up
Keep HTTP credential extraction separate from identity validation and persistence concerns.
Q5. What is HttpAuthenticationMechanism?
Answer
HttpAuthenticationMechanism defines how an HTTP request is authenticated.
It can:
- Read credentials from the request
- Validate credentials
- Notify the container about success
- Reject invalid authentication
- Redirect to a login page
- Continue unauthenticated processing where allowed
Main Method
AuthenticationStatus validateRequest(
HttpServletRequest request,
HttpServletResponse response,
HttpMessageContext context
);
Basic Authentication Mechanism Example
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.security.enterprise.AuthenticationStatus;
import jakarta.security.enterprise.authentication.mechanism.http.HttpAuthenticationMechanism;
import jakarta.security.enterprise.authentication.mechanism.http.HttpMessageContext;
import jakarta.security.enterprise.credential.UsernamePasswordCredential;
import jakarta.security.enterprise.identitystore.CredentialValidationResult;
import jakarta.security.enterprise.identitystore.IdentityStoreHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@ApplicationScoped
public class CustomAuthenticationMechanism
implements HttpAuthenticationMechanism {
private final IdentityStoreHandler
identityStoreHandler;
@Inject
public CustomAuthenticationMechanism(
IdentityStoreHandler
identityStoreHandler
) {
this.identityStoreHandler =
identityStoreHandler;
}
@Override
public AuthenticationStatus
validateRequest(
HttpServletRequest request,
HttpServletResponse response,
HttpMessageContext context
) {
String username =
request.getParameter(
"username"
);
String password =
request.getParameter(
"password"
);
if (
username == null
|| password == null
) {
return context.doNothing();
}
CredentialValidationResult result =
identityStoreHandler.validate(
new UsernamePasswordCredential(
username,
password
)
);
if (
result.getStatus()
== CredentialValidationResult
.Status.VALID
) {
return context
.notifyContainerAboutLogin(
result
);
}
return context.responseUnauthorized();
}
}
Authentication Flow
sequenceDiagram
participant Client
participant Container
participant Mechanism
participant IdentityStore
participant Resource
Client->>Container: HTTP request
Container->>Mechanism: validateRequest
Mechanism->>IdentityStore: Validate credentials
alt Valid
IdentityStore-->>Mechanism: Principal and groups
Mechanism->>Container: notifyContainerAboutLogin
Container->>Resource: Invoke protected resource
Resource-->>Client: Success
else Invalid
IdentityStore-->>Mechanism: Invalid
Mechanism-->>Client: 401 Unauthorized
end
Common Mistake
Logging raw passwords during authentication debugging.
Senior Follow-up
Authentication mechanisms must avoid credential leakage, timing attacks, open redirects, and inconsistent failure messages.
Q6. What is SecurityContext?
Answer
SecurityContext gives application code access to the current caller's security information.
It can be used to:
- Get the caller principal
- Check whether the caller is in a role
- Check access to a web resource
- Determine authentication status
Injection Example
import jakarta.inject.Inject;
import jakarta.security.enterprise.SecurityContext;
@ApplicationScoped
public class CurrentUserService {
private final SecurityContext
securityContext;
@Inject
public CurrentUserService(
SecurityContext securityContext
) {
this.securityContext =
securityContext;
}
public String currentUsername() {
return securityContext
.getCallerPrincipal()
.getName();
}
public boolean isAdministrator() {
return securityContext
.isCallerInRole("ADMIN");
}
}
REST Resource Example
@Path("/profile")
@Produces(MediaType.APPLICATION_JSON)
public class ProfileResource {
@Inject
private SecurityContext
securityContext;
@GET
public ProfileResponse profile() {
String username =
securityContext
.getCallerPrincipal()
.getName();
return new ProfileResponse(
username
);
}
}
Security Context Flow
flowchart TD
A[Authenticated Request] --> B[Container Security Identity]
B --> C[SecurityContext]
C --> D[Caller Principal]
C --> E[Role Checks]
C --> F[Resource Access Check]
Common Mistake
Storing the current user in a static variable.
Senior Follow-up
Caller identity is request-specific and should be obtained from the active security context.
Q7. What is role-based access control?
Answer
Role-Based Access Control, or RBAC, grants permissions based on roles assigned to a caller.
Common Roles
ADMINCUSTOMERSUPPORT_AGENTCLAIMS_ADJUSTERMANAGERAUDITOR
RBAC Flow
flowchart LR
A[User] --> B[Assigned Roles]
B --> C[ADMIN]
B --> D[SUPPORT_AGENT]
C --> E[Permissions]
D --> E
E --> F[Protected Resources]
Example
@RolesAllowed("ADMIN")
public void deleteCustomer(
Long customerId
) {
customerRepository.delete(
customerId
);
}
Multi-Role Example
@RolesAllowed({
"ADMIN",
"SUPPORT_AGENT"
})
public CustomerResponse findCustomer(
Long customerId
) {
return customerService.findCustomer(
customerId
);
}
RBAC Limitations
A role may grant general capability, but the application may still need to check:
- Record ownership
- Geographic scope
- Department
- Approval amount
- Tenant
- Resource classification
- Current workflow state
Example
public AccountResponse findAccount(
Long accountId
) {
Account account =
accountRepository
.findById(accountId)
.orElseThrow();
String caller =
securityContext
.getCallerPrincipal()
.getName();
if (
!account.getOwnerUsername()
.equals(caller)
&& !securityContext
.isCallerInRole("ADMIN")
) {
throw new ForbiddenException();
}
return accountMapper.toResponse(
account
);
}
Common Mistake
Assuming a CUSTOMER role allows every customer to access every customer record.
Senior Follow-up
Combine coarse-grained RBAC with fine-grained attribute or ownership checks.
Q8. What do @RolesAllowed, @PermitAll, and @DenyAll do?
Answer
These annotations define declarative method-level access control.
@RolesAllowed
Allows only specified roles.
@RolesAllowed("ADMIN")
public void suspendUser(
Long userId
) {
}
@PermitAll
Allows all callers.
@PermitAll
public HealthResponse health() {
return new HealthResponse("UP");
}
@DenyAll
Blocks every caller.
@DenyAll
public void deprecatedOperation() {
}
Annotation Flow
flowchart TD
A[Method Invocation] --> B{Security Annotation}
B -->|RolesAllowed| C[Check Caller Role]
B -->|PermitAll| D[Allow Invocation]
B -->|DenyAll| E[Reject Invocation]
C --> F{Role Match?}
F -->|Yes| D
F -->|No| E
Example Resource
@Path("/admin/users")
@Produces(MediaType.APPLICATION_JSON)
public class AdminUserResource {
@GET
@RolesAllowed("ADMIN")
public List<UserResponse> findUsers() {
return userService.findUsers();
}
@GET
@Path("/status")
@PermitAll
public StatusResponse status() {
return new StatusResponse(
"AVAILABLE"
);
}
}
Common Mistake
Adding @PermitAll to a class and assuming a method-level role annotation will always override it consistently without testing runtime behavior.
Senior Follow-up
Keep security annotations close to protected operations and verify enforcement through integration tests.
Q9. How is form-based authentication implemented?
Answer
Form-based authentication collects credentials through an HTML form and authenticates the user through the container.
A standard Jakarta Security mechanism can be configured with a login page and error page.
Example
import jakarta.security.enterprise.authentication.mechanism.http.FormAuthenticationMechanismDefinition;
import jakarta.security.enterprise.authentication.mechanism.http.LoginToContinue;
@FormAuthenticationMechanismDefinition(
loginToContinue = @LoginToContinue(
loginPage = "/login.html",
errorPage = "/login-error.html",
useForwardToLogin = false
)
)
@ApplicationScoped
public class SecurityConfiguration {
}
Form Login Flow
sequenceDiagram
participant Browser
participant ProtectedPage
participant LoginPage
participant SecurityMechanism
participant IdentityStore
Browser->>ProtectedPage: Request protected page
ProtectedPage-->>Browser: Redirect to login
Browser->>LoginPage: Load login form
Browser->>SecurityMechanism: Submit username and password
SecurityMechanism->>IdentityStore: Validate credentials
alt Valid
IdentityStore-->>SecurityMechanism: Principal and roles
SecurityMechanism-->>Browser: Redirect to original page
else Invalid
IdentityStore-->>SecurityMechanism: Invalid
SecurityMechanism-->>Browser: Redirect to error page
end
Security Considerations
- Use HTTPS.
- Protect against CSRF.
- Regenerate session ID after login.
- Use secure session cookies.
- Avoid storing passwords in session.
- Limit login attempts.
- Add account lockout carefully.
- Provide generic failure messages.
Common Mistake
Sending login credentials over HTTP.
Senior Follow-up
Modern browser applications often delegate authentication to an identity provider rather than maintaining custom password login pages.
Q10. How is basic authentication implemented?
Answer
HTTP Basic Authentication sends a username and password in the Authorization header using Base64 encoding.
Base64 is not encryption.
Therefore, Basic Authentication must be used only over HTTPS.
Example Configuration
import jakarta.security.enterprise.authentication.mechanism.http.BasicAuthenticationMechanismDefinition;
@BasicAuthenticationMechanismDefinition(
realmName = "application-realm"
)
@ApplicationScoped
public class BasicSecurityConfiguration {
}
Header Example
Authorization: Basic dXNlcjpwYXNzd29yZA==
Flow
sequenceDiagram
participant Client
participant API
participant IdentityStore
Client->>API: Request without credentials
API-->>Client: 401 with WWW-Authenticate
Client->>API: Request with Basic Authorization header
API->>IdentityStore: Validate username and password
alt Valid
IdentityStore-->>API: Caller identity
API-->>Client: Protected response
else Invalid
IdentityStore-->>API: Invalid
API-->>Client: 401 Unauthorized
end
Good Use Cases
- Internal administrative tooling
- Simple service integration
- Development environments
- Controlled legacy environments
Poor Use Cases
- Public consumer applications
- Long-lived credentials in mobile apps
- High-security internet-facing APIs
- Systems requiring modern federation
Common Mistake
Assuming Base64 protects credentials.
Senior Follow-up
For modern service-to-service security, short-lived tokens or mutual TLS are often safer than reusable passwords.
Q11. How does JWT authentication work?
Answer
JWT authentication uses a signed token containing claims about the caller.
A JWT typically includes:
- Subject
- Issuer
- Audience
- Expiration
- Issued-at timestamp
- Roles or groups
- Token identifier
- Additional application claims
Token Structure
header.payload.signature
JWT Validation Flow
sequenceDiagram
participant Client
participant IdentityProvider
participant API
participant Resource
Client->>IdentityProvider: Authenticate
IdentityProvider-->>Client: Signed access token
Client->>API: Authorization Bearer token
API->>API: Validate signature
API->>API: Validate issuer
API->>API: Validate audience
API->>API: Validate expiration
API->>API: Extract roles and subject
alt Valid
API->>Resource: Invoke protected resource
Resource-->>Client: Success
else Invalid
API-->>Client: 401 Unauthorized
end
Authorization Header
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Important Validation Checks
- Signature is valid
- Algorithm is allowed
- Token is not expired
- Token is active
- Issuer is trusted
- Audience matches the API
- Required claims exist
- Key is current
- Token type is appropriate
JWT Claims Example
{
"sub": "[email protected]",
"iss": "https://identity.example.com",
"aud": "claims-api",
"exp": 1783864800,
"groups": [
"CUSTOMER",
"CLAIM_VIEWER"
]
}
Common Mistake
Only decoding the JWT and trusting its contents without validating its signature.
Senior Follow-up
JWT validation should use trusted libraries and controlled key management rather than custom cryptographic code.
Q12. How is security applied to Jakarta REST endpoints?
Answer
Jakarta REST endpoints can be protected using:
- Security annotations
- Request filters
- Container security
- Security context checks
- Token validation
- Fine-grained business authorization
Resource Example
@Path("/claims")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ClaimResource {
private final ClaimService claimService;
@Inject
public ClaimResource(
ClaimService claimService
) {
this.claimService =
claimService;
}
@GET
@RolesAllowed({
"CLAIM_VIEWER",
"CLAIM_ADJUSTER"
})
public List<ClaimSummary> findClaims() {
return claimService.findClaims();
}
@POST
@RolesAllowed("CUSTOMER")
public Response createClaim(
@Valid
CreateClaimRequest request
) {
Long claimId =
claimService.createClaim(
request
);
return Response
.status(Response.Status.CREATED)
.entity(
new CreateClaimResponse(
claimId
)
)
.build();
}
@POST
@Path("/{id}/approve")
@RolesAllowed("CLAIM_ADJUSTER")
public Response approveClaim(
@PathParam("id")
Long claimId
) {
claimService.approveClaim(
claimId
);
return Response
.noContent()
.build();
}
}
REST Security Pipeline
flowchart TD
A[HTTP Request] --> B[TLS]
B --> C[Authentication Filter or Mechanism]
C --> D[Token or Credential Validation]
D --> E[Security Context]
E --> F[Role Check]
F --> G[Resource Ownership Check]
G --> H[Input Validation]
H --> I[Application Service]
I --> J[Audit Logging]
Response Behavior
- Unauthenticated:
401 Unauthorized - Authenticated but not allowed:
403 Forbidden - Hidden resource: sometimes
404 Not Found - Expired token: commonly
401 Unauthorized
Common Mistake
Returning 403 Forbidden when no caller identity exists.
Senior Follow-up
Avoid exposing whether sensitive resources exist when the caller is not authorized to know.
Q13. How should passwords be stored securely?
Answer
Passwords should never be stored in plain text or encrypted with a reversible algorithm.
They should be processed using a dedicated password-hashing algorithm designed for credential storage.
Suitable Approaches
- Argon2
- bcrypt
- scrypt
- PBKDF2
Password Storage Flow
flowchart TD
A[User Password] --> B[Generate Unique Salt]
B --> C[Password Hashing Algorithm]
C --> D[Store Hash Parameters and Result]
D --> E[Database]
Authentication Flow
sequenceDiagram
participant User
participant Application
participant Database
participant PasswordHasher
User->>Application: Submit password
Application->>Database: Load password hash
Database-->>Application: Stored hash and parameters
Application->>PasswordHasher: Verify submitted password
PasswordHasher-->>Application: Match or no match
Example Service
@ApplicationScoped
public class PasswordService {
public String hash(
String rawPassword
) {
// Use a trusted password-hashing library.
throw new UnsupportedOperationException(
"Provider implementation required"
);
}
public boolean matches(
String rawPassword,
String storedHash
) {
// Verify using the provider that created the hash.
throw new UnsupportedOperationException(
"Provider implementation required"
);
}
}
Important Practices
- Use a unique salt for every password.
- Configure sufficient work factor.
- Rehash when security settings improve.
- Never log passwords.
- Never send passwords in URLs.
- Do not return password hashes through APIs.
- Protect reset tokens.
- Apply rate limiting.
Common Mistake
Using SHA-256 directly for password storage.
Senior Follow-up
General-purpose hash functions are too fast and are not designed to resist large-scale password guessing.
Q14. What are common Jakarta Security mistakes?
Answer
Common mistakes include:
- Storing passwords in plain text.
- Using weak password hashing.
- Logging credentials or tokens.
- Trusting decoded JWT claims without signature verification.
- Ignoring issuer or audience validation.
- Using Basic Authentication without HTTPS.
- Returning detailed login failure reasons.
- Using roles without ownership checks.
- Storing caller identity in static fields.
- Using long-lived tokens without revocation strategy.
- Failing to regenerate session ID after login.
- Using insecure cookies.
- Allowing unlimited login attempts.
- Hardcoding secrets.
- Treating CORS as authentication.
- Disabling CSRF protection without understanding the client model.
- Returning stack traces to clients.
- Using one administrator role for every privileged action.
- Forgetting service-to-service authentication.
- Failing to audit security-sensitive actions.
Dangerous JWT Flow
flowchart TD
A[Receive JWT] --> B[Base64 Decode]
B --> C[Read Role Claim]
C --> D[Trust Token]
D --> E[Security Compromise]
Correct JWT Flow
flowchart TD
A[Receive JWT] --> B[Parse Token Safely]
B --> C[Validate Signature]
C --> D[Validate Issuer]
D --> E[Validate Audience]
E --> F[Validate Expiration]
F --> G[Validate Required Claims]
G --> H[Create Security Identity]
Common Mistake
Assuming frontend route protection secures backend APIs.
Senior Follow-up
Security controls must be enforced on the server regardless of frontend behavior.
Q15. What are senior-level Jakarta Security best practices?
Answer
Senior developers should design security as a layered architecture rather than one annotation or filter.
Best Practices
- Use HTTPS everywhere.
- Delegate authentication to a trusted identity provider where practical.
- Use short-lived access tokens.
- Validate all token claims.
- Use least privilege.
- Keep roles focused and meaningful.
- Add fine-grained resource authorization.
- Use secure password hashing.
- Protect secrets in a secret manager.
- Use secure session cookies.
- Regenerate session ID after login.
- Apply rate limiting.
- Implement login lockout carefully.
- Add security audit logs.
- Avoid logging credentials or tokens.
- Validate redirect targets.
- Use CSRF protection for cookie-based authentication.
- Configure CORS narrowly.
- Add security headers.
- Test authorization failures.
- Review access periodically.
- Plan key rotation and token revocation.
- Monitor suspicious authentication behavior.
- Protect administrative APIs separately.
- Design for multi-tenant isolation.
Security Design Flow
flowchart TD
A[Identify Protected Resource] --> B[Define Caller Types]
B --> C[Select Authentication Method]
C --> D[Define Roles and Permissions]
D --> E[Add Ownership and Policy Checks]
E --> F[Define Token or Session Lifetime]
F --> G[Add Audit Logging]
G --> H[Add Rate Limits and Alerts]
H --> I[Test Positive and Negative Paths]
Senior Follow-up
Security must be continuously monitored, tested, reviewed, and updated as threats and system architecture evolve.
Jakarta Security Architecture
flowchart TD
A[Browser or API Client] --> B[TLS Endpoint]
B --> C[Authentication Mechanism]
C --> D[IdentityStoreHandler]
D --> E[IdentityStore]
E --> F[Database or Directory]
D --> G[Principal and Groups]
G --> H[SecurityContext]
H --> I[Role Authorization]
I --> J[Business Authorization]
J --> K[Jakarta REST Resource]
K --> L[Application Service]
L --> M[Database]
Authentication Status
HttpAuthenticationMechanism can return authentication status values representing outcomes such as:
- Success
- Failure
- Continue processing
- Send response
Conceptual Flow
flowchart TD
A[validateRequest] --> B{Credentials Present?}
B -->|No| C[Do Nothing or Challenge]
B -->|Yes| D[Validate Credentials]
D --> E{Valid?}
E -->|Yes| F[Notify Container About Login]
E -->|No| G[Return Unauthorized Response]
Caller Principal
The caller principal represents the authenticated identity.
Principal principal =
securityContext
.getCallerPrincipal();
String callerName =
principal.getName();
Typical Uses
- Audit logging
- Ownership checks
- Tenant resolution
- User-specific queries
- Business rules
- Response personalization
Warning
Do not use user-controlled request headers as a trusted principal.
Incorrect:
String currentUser =
request.getHeader(
"X-User"
);
Correct:
String currentUser =
securityContext
.getCallerPrincipal()
.getName();
Database Identity Model
erDiagram
USERS ||--o{ USER_ROLES : has
ROLES ||--o{ USER_ROLES : assigned
USERS {
bigint id PK
varchar username
varchar password_hash
boolean active
timestamp locked_until
}
ROLES {
bigint id PK
varchar role_name
}
USER_ROLES {
bigint user_id FK
bigint role_id FK
}
Recommended Constraints
ALTER TABLE users
ADD CONSTRAINT uk_users_username
UNIQUE (username);
ALTER TABLE roles
ADD CONSTRAINT uk_roles_role_name
UNIQUE (role_name);
Database IdentityStore Definition
Jakarta Security supports declarative database identity-store configuration.
import jakarta.security.enterprise.identitystore.DatabaseIdentityStoreDefinition;
@DatabaseIdentityStoreDefinition(
dataSourceLookup =
"java:app/jdbc/ApplicationDataSource",
callerQuery =
"""
SELECT password_hash
FROM users
WHERE username = ?
AND active = true
""",
groupsQuery =
"""
SELECT r.role_name
FROM roles r
JOIN user_roles ur
ON ur.role_id = r.id
JOIN users u
ON u.id = ur.user_id
WHERE u.username = ?
""",
hashAlgorithm =
CustomPasswordHash.class
)
@ApplicationScoped
public class DatabaseSecurityConfiguration {
}
Flow
flowchart TD
A[Username Password Credential] --> B[Database Identity Store]
B --> C[Caller Query]
C --> D[Password Hash Verification]
D --> E{Valid?}
E -->|No| F[Invalid Result]
E -->|Yes| G[Groups Query]
G --> H[Principal and Roles]
LDAP IdentityStore Concept
flowchart LR
A[Authentication Mechanism] --> B[LDAP Identity Store]
B --> C[Directory Server]
C --> D[User Entry]
C --> E[Group Membership]
Good Use Cases
- Enterprise employee authentication
- Centralized directory
- Existing organization groups
- Internal applications
Considerations
- Connection security
- Directory availability
- Group-mapping rules
- Nested groups
- Search performance
- Timeout configuration
- Failover behavior
Custom Authentication Mechanism with Header Token
@ApplicationScoped
public class ApiTokenAuthenticationMechanism
implements HttpAuthenticationMechanism {
private final ApiTokenService
apiTokenService;
@Inject
public ApiTokenAuthenticationMechanism(
ApiTokenService apiTokenService
) {
this.apiTokenService =
apiTokenService;
}
@Override
public AuthenticationStatus
validateRequest(
HttpServletRequest request,
HttpServletResponse response,
HttpMessageContext context
) {
String token =
request.getHeader(
"X-API-Token"
);
if (token == null) {
return context.doNothing();
}
return apiTokenService
.authenticate(token)
.map(
identity ->
context
.notifyContainerAboutLogin(
identity.principal(),
identity.roles()
)
)
.orElseGet(
context::responseUnauthorized
);
}
}
Security Warning
API tokens should be:
- Random and high entropy
- Stored as hashes where possible
- Scoped
- Rotatable
- Expirable
- Audited
- Protected in transit
- Revocable
Session-Based Authentication Flow
sequenceDiagram
participant Browser
participant Application
participant IdentityStore
participant SessionStore
Browser->>Application: Submit credentials
Application->>IdentityStore: Validate credentials
alt Valid
IdentityStore-->>Application: Principal and roles
Application->>SessionStore: Create authenticated session
Application-->>Browser: Secure session cookie
Browser->>Application: Later request with cookie
Application->>SessionStore: Resolve security identity
Application-->>Browser: Protected response
else Invalid
IdentityStore-->>Application: Invalid
Application-->>Browser: Generic login failure
end
Token-Based Authentication Flow
sequenceDiagram
participant Client
participant IdentityProvider
participant API
Client->>IdentityProvider: Authenticate
IdentityProvider-->>Client: Access token
Client->>API: Bearer access token
API->>API: Validate token
API-->>Client: Protected response
Session vs Token
| Session Authentication | Token Authentication |
|---|---|
| Server stores session state | Token carries claims |
| Uses session cookie | Uses Authorization header |
| Easy revocation through session store | Revocation may require extra strategy |
| Good for browser applications | Good for APIs and distributed systems |
| CSRF protection needed for cookies | Bearer-token theft remains a risk |
| Central session control | Easier horizontal scaling |
JWT Header and Payload
Header
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-2026-07"
}
Payload
{
"sub": "user-101",
"iss": "https://id.example.com",
"aud": "order-api",
"iat": 1783857600,
"exp": 1783861200,
"jti": "token-abc-101",
"groups": [
"CUSTOMER"
]
}
Signature
The signature protects token integrity.
It does not encrypt the payload.
Important
Do not place secrets or sensitive personal data inside a JWT unless the token is additionally encrypted and the architecture requires it.
JWT Key Rotation
flowchart TD
A[Identity Provider] --> B[Current Signing Key]
A --> C[Previous Verification Key]
B --> D[Issue New Tokens]
C --> E[Verify Older Unexpired Tokens]
D --> F[Publish Key Set]
E --> F
F --> G[API Retrieves Trusted Keys]
Best Practices
- Use key identifiers.
- Publish trusted public keys securely.
- Cache keys with refresh policy.
- Support overlapping rotation.
- Reject unknown algorithms.
- Monitor key-fetch failures.
- Remove old keys after token expiration window.
Access Token vs Refresh Token
| Access Token | Refresh Token |
|---|---|
| Short lifetime | Longer lifetime |
| Sent to APIs | Sent only to token endpoint |
| Contains API authorization claims | Used to obtain new access token |
| Higher exposure frequency | Must be stored more securely |
| Usually bearer token | Often rotated |
Common Mistake
Sending refresh tokens to normal application APIs.
Token Revocation Strategies
- Short token lifetime
- Token denylist
- Session-bound tokens
- Token introspection
- User security version
- Key rotation
- Refresh-token revocation
- Account disable checks
Revocation Flow
flowchart TD
A[Token Presented] --> B[Validate Signature and Claims]
B --> C{Revocation Check Required?}
C -->|No| D[Allow]
C -->|Yes| E[Check Token Status]
E --> F{Revoked?}
F -->|Yes| G[Reject]
F -->|No| D
Fine-Grained Authorization
RBAC answers broad questions.
Fine-grained authorization evaluates resource attributes and business rules.
Example Policy
A claims adjuster may approve a claim only when:
- The caller has CLAIM_ADJUSTER role.
- The claim belongs to the caller's region.
- The claim amount is below the caller's approval limit.
- The claim is currently in REVIEW status.
Flow
flowchart TD
A[Approve Claim Request] --> B[Check CLAIM_ADJUSTER Role]
B --> C[Load Claim]
C --> D[Check Region]
D --> E[Check Approval Limit]
E --> F[Check Workflow Status]
F --> G{All Checks Pass?}
G -->|Yes| H[Approve Claim]
G -->|No| I[Reject with 403 or Business Error]
Service Example
@Transactional
public void approveClaim(
Long claimId
) {
Claim claim =
claimRepository
.findById(claimId)
.orElseThrow();
UserAuthorizationProfile profile =
authorizationService
.currentProfile();
if (
!securityContext.isCallerInRole(
"CLAIM_ADJUSTER"
)
) {
throw new ForbiddenException();
}
if (
!claim.getRegion()
.equals(profile.region())
) {
throw new ForbiddenException();
}
if (
claim.getAmount()
.compareTo(
profile.approvalLimit()
) > 0
) {
throw new ForbiddenException();
}
claim.approve();
}
Multi-Tenant Authorization
Every tenant-specific query should enforce tenant isolation.
Unsafe Query
entityManager.find(
Customer.class,
customerId
);
Safer Query
Customer customer =
entityManager.createQuery(
"""
select c
from Customer c
where c.id = :customerId
and c.tenantId = :tenantId
""",
Customer.class
)
.setParameter(
"customerId",
customerId
)
.setParameter(
"tenantId",
currentTenantId
)
.getSingleResult();
Tenant Flow
flowchart TD
A[Authenticated Caller] --> B[Resolve Trusted Tenant]
B --> C[Apply Tenant Filter]
C --> D[Query Tenant-Owned Resource]
D --> E{Resource in Tenant?}
E -->|Yes| F[Continue]
E -->|No| G[Reject or Return Not Found]
Common Mistake
Trusting a tenant ID directly from an unvalidated request header.
Secure Cookie Configuration
Important cookie attributes include:
SecureHttpOnlySameSite- Limited path
- Limited domain
- Appropriate lifetime
Conceptual Header
Set-Cookie:
SESSION=abc123;
Secure;
HttpOnly;
SameSite=Lax;
Path=/;
Max-Age=1800
Cookie Protection
flowchart TD
A[Session Cookie] --> B[Secure]
A --> C[HttpOnly]
A --> D[SameSite]
A --> E[Short Lifetime]
A --> F[Server-Side Revocation]
CSRF Protection
CSRF is primarily a concern when browsers automatically attach credentials such as cookies.
Attack Flow
sequenceDiagram
participant User
participant MaliciousSite
participant Bank
User->>Bank: Login and receive session cookie
User->>MaliciousSite: Visit malicious page
MaliciousSite->>Bank: Forged request
Note over Bank: Browser automatically attaches cookie
Defenses
- CSRF tokens
- SameSite cookies
- Origin validation
- Referer validation where appropriate
- Re-authentication for sensitive actions
- Avoid state changes through GET
- Use Authorization header tokens where suitable
Common Mistake
Assuming CORS prevents CSRF.
CORS Security
CORS controls which browser origins may access responses.
It is not authentication.
Safer Configuration
- Allow only trusted origins.
- Limit methods.
- Limit headers.
- Avoid wildcard origin with credentials.
- Validate preflight behavior.
- Do not reflect arbitrary origins.
Flow
flowchart TD
A[Browser Cross-Origin Request] --> B[Origin Header]
B --> C[Server CORS Policy]
C --> D{Origin Allowed?}
D -->|Yes| E[Return CORS Headers]
D -->|No| F[Browser Blocks Response Access]
Security Headers
Common security headers include:
- Content Security Policy
- X-Content-Type-Options
- Strict-Transport-Security
- Referrer-Policy
- Permissions-Policy
- Frame restrictions
Response Filter Example
@Provider
public class SecurityHeadersFilter
implements ContainerResponseFilter {
@Override
public void filter(
ContainerRequestContext request,
ContainerResponseContext response
) {
response
.getHeaders()
.putSingle(
"X-Content-Type-Options",
"nosniff"
);
response
.getHeaders()
.putSingle(
"Referrer-Policy",
"no-referrer"
);
response
.getHeaders()
.putSingle(
"Content-Security-Policy",
"default-src 'self'"
);
}
}
Rate Limiting Login Attempts
flowchart TD
A[Login Attempt] --> B[Identify Account and Source]
B --> C[Increment Attempt Counter]
C --> D{Limit Exceeded?}
D -->|No| E[Validate Credentials]
D -->|Yes| F[Delay or Reject]
E --> G{Valid?}
G -->|Yes| H[Reset or Reduce Counter]
G -->|No| I[Record Failure]
Important
Avoid permanent denial-of-service through careless account lockout.
Consider:
- Progressive delays
- Temporary lockout
- Device reputation
- IP reputation
- MFA
- User notification
- Administrative recovery
Multi-Factor Authentication
MFA combines at least two factor categories:
- Something the user knows
- Something the user has
- Something the user is
Flow
sequenceDiagram
participant User
participant LoginService
participant IdentityStore
participant MFAService
User->>LoginService: Username and password
LoginService->>IdentityStore: Validate password
IdentityStore-->>LoginService: Valid
LoginService->>MFAService: Request second factor
MFAService-->>User: Challenge
User->>MFAService: Submit code
MFAService-->>LoginService: Verified
LoginService-->>User: Authentication complete
Audit Logging
Security-sensitive actions should be audited.
Common Audit Events
- Login success
- Login failure
- Password reset
- MFA change
- Role assignment
- Account lock
- Privileged data access
- Administrative update
- Token revocation
- DLQ replay
- Security-policy change
Audit Record
public record SecurityAuditEvent(
String eventType,
String actor,
String target,
Instant occurredAt,
String correlationId,
String outcome
) {
}
Important
Do not include:
- Plain-text passwords
- Full access tokens
- Session IDs
- Private keys
- Sensitive personal content
Generic Authentication Failure
Unsafe:
Password is incorrect.
Safer:
Invalid username or password.
Why?
Detailed failures can reveal:
- Whether an account exists
- Whether an account is locked
- Whether the password was correct
- Whether MFA is enabled
Internal logs may retain more detail, but client responses should be carefully designed.
Secret Management
Do not hardcode:
- Database passwords
- JWT private keys
- API tokens
- Encryption keys
- OAuth client secrets
Recommended Flow
flowchart TD
A[Application Startup] --> B[Secret Manager]
B --> C[Retrieve Authorized Secret]
C --> D[Use in Memory]
D --> E[Rotate Secret]
E --> F[Refresh Application Safely]
Good Practices
- Least-privilege access
- Rotation
- Auditing
- Environment separation
- No source-control storage
- No logs
- Short-lived credentials where possible
OAuth 2.0 and OpenID Connect Context
OAuth 2.0 is commonly used for delegated authorization.
OpenID Connect adds identity information on top of OAuth 2.0.
Architecture
sequenceDiagram
participant User
participant Client
participant IdentityProvider
participant API
User->>Client: Start login
Client->>IdentityProvider: Authorization request
IdentityProvider->>User: Authenticate
IdentityProvider-->>Client: Authorization result
Client->>IdentityProvider: Exchange for tokens
IdentityProvider-->>Client: ID token and access token
Client->>API: Access token
API->>API: Validate token and authorize
API-->>Client: Protected data
Important Distinction
- ID token identifies the user to the client.
- Access token authorizes calls to the API.
- Refresh token obtains new access tokens.
- An ID token should not automatically be treated as an API access token.
Service-to-Service Security
Common approaches include:
- OAuth client credentials
- Mutual TLS
- Signed service tokens
- Workload identity
- Short-lived platform credentials
Flow
sequenceDiagram
participant ServiceA
participant IdentityProvider
participant ServiceB
ServiceA->>IdentityProvider: Client authentication
IdentityProvider-->>ServiceA: Short-lived access token
ServiceA->>ServiceB: Bearer token
ServiceB->>ServiceB: Validate service identity
ServiceB-->>ServiceA: Protected response
Common Mistake
Using one shared static API key across all services.
Security Testing Strategy
Test:
- Successful authentication
- Invalid credentials
- Locked account
- Expired account
- Missing token
- Expired token
- Wrong issuer
- Wrong audience
- Invalid signature
- Missing role
- Wrong tenant
- Wrong resource owner
- Admin-only operation
- Session fixation protection
- CSRF failure
- CORS restrictions
- Rate limiting
- Audit generation
Test Matrix
flowchart TD
A[Security Test Suite] --> B[Authentication Tests]
A --> C[Authorization Tests]
A --> D[Token Validation Tests]
A --> E[Session Tests]
A --> F[Tenant Isolation Tests]
A --> G[Audit Tests]
Authorization Integration Test Example
@Test
void customerMustNotAccessAnotherCustomersAccount() {
String customerAToken =
tokenFactory.issueToken(
"customer-a",
Set.of("CUSTOMER")
);
given()
.header(
"Authorization",
"Bearer " + customerAToken
)
.when()
.get(
"/accounts/customer-b-account"
)
.then()
.statusCode(403);
}
The exact testing library depends on the project, but negative authorization tests are essential.
Threat Modeling
A simple threat-modeling process asks:
- What are the assets?
- Who are the actors?
- What are the trust boundaries?
- How can authentication fail?
- How can authorization fail?
- What data could be exposed?
- What dependencies can be abused?
- What must be audited?
- How will incidents be detected?
Threat Model Flow
flowchart TD
A[Identify Assets] --> B[Identify Attackers]
B --> C[Map Data Flows]
C --> D[Identify Trust Boundaries]
D --> E[Identify Threats]
E --> F[Define Controls]
F --> G[Test Controls]
G --> H[Monitor Residual Risk]
Security Layers
flowchart TD
A[Network Security] --> B[TLS]
B --> C[Authentication]
C --> D[Authorization]
D --> E[Input Validation]
E --> F[Business Rules]
F --> G[Database Constraints]
G --> H[Audit and Monitoring]
No single control is sufficient.
Production Security Architecture
flowchart TD
A[Client] --> B[API Gateway]
B --> C[TLS Termination]
C --> D[Rate Limiting]
D --> E[Token Validation]
E --> F[Jakarta REST API]
F --> G[SecurityContext]
G --> H[Role Check]
H --> I[Ownership and Policy Check]
I --> J[Application Service]
J --> K[Database]
J --> L[Audit Event]
L --> M[Security Monitoring]
Authentication Decision Matrix
| Scenario | Recommended Approach |
|---|---|
| Browser enterprise application | OpenID Connect |
| Public mobile application | OAuth 2.0 with PKCE |
| Internal REST API | Short-lived bearer token |
| Service-to-service | Client credentials or workload identity |
| Legacy internal tool | Basic authentication over TLS, if unavoidable |
| Administrative portal | Strong authentication with MFA |
| Consumer password login | Prefer dedicated identity provider |
| Machine integration | Scoped API credential or OAuth client |
Authorization Decision Matrix
| Requirement | Recommended Control |
|---|---|
| Admin-only endpoint | Role check |
| User's own record | Ownership check |
| Regional access | Attribute check |
| Approval amount | Business-policy check |
| Tenant isolation | Tenant-scoped query |
| Sensitive operation | Step-up authentication |
| Shared service permission | Scope or service role |
| Record classification | Policy-based authorization |
Common Jakarta Security Anti-Patterns
Frontend-Only Authorization
Hide the Admin button in the UI.
This does not protect the backend.
Client-Supplied Role
X-Role: ADMIN
Never trust client-supplied authorization claims without cryptographic or trusted gateway validation.
Long-Lived Bearer Token
A stolen bearer token remains usable until it expires or is revoked.
Role Explosion
ADMIN_READ_CUSTOMER_US_EAST_TIER_1
ADMIN_READ_CUSTOMER_US_EAST_TIER_2
...
Excessively granular roles become difficult to manage.
Use policy or attributes for dynamic conditions.
Error Response Examples
Unauthenticated
{
"code": "UNAUTHENTICATED",
"message": "Authentication is required",
"correlationId": "req-1001"
}
Forbidden
{
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action",
"correlationId": "req-1002"
}
Avoid revealing sensitive authorization details.
Security Monitoring Metrics
Monitor:
- Login success rate
- Login failure rate
- Locked accounts
- Token-validation failures
- Invalid signatures
- Expired tokens
- Wrong-audience attempts
- Forbidden-response rate
- Administrative operations
- Password-reset volume
- MFA failures
- Rate-limit triggers
- Suspicious IP activity
- Tenant-isolation failures
- Session creation and revocation
- Security audit pipeline health
Monitoring Flow
flowchart TD
A[Security Event] --> B[Structured Audit Log]
B --> C[Security Analytics]
C --> D[Detection Rule]
D --> E{Suspicious?}
E -->|Yes| F[Alert]
E -->|No| G[Store for Investigation]
Incident Response Preparation
Plan for:
- Compromised account
- Stolen token
- Leaked signing key
- Exposed API credential
- Unauthorized role assignment
- Session theft
- Mass login attack
- Tenant data exposure
Response Flow
flowchart TD
A[Security Incident Detected] --> B[Contain]
B --> C[Revoke Credentials]
C --> D[Rotate Keys]
D --> E[Preserve Evidence]
E --> F[Assess Impact]
F --> G[Notify Stakeholders]
G --> H[Remediate Root Cause]
H --> I[Improve Controls]
Jakarta Security Checklist
Authentication
- Trusted credential source
- Secure transport
- Strong password hashing
- MFA where appropriate
- Generic failure responses
- Rate limiting
- Account status checks
Authorization
- Least privilege
- Role checks
- Ownership checks
- Tenant isolation
- Workflow checks
- Sensitive-operation protection
Tokens
- Signature validation
- Issuer validation
- Audience validation
- Expiration validation
- Algorithm allowlist
- Key rotation
- Revocation strategy
Sessions
- Secure cookies
- HttpOnly
- SameSite
- Session-ID rotation
- Idle timeout
- Absolute timeout
- Server-side invalidation
Operations
- Audit logs
- Alerts
- Secret rotation
- Security testing
- Access reviews
- Incident response
Senior Security Checklist
Trusted Authentication Source
│
▼
Short-Lived Identity
│
▼
Least-Privilege Roles
│
▼
Ownership and Policy Checks
│
▼
Secure Token or Session Handling
│
▼
Audit and Monitoring
│
▼
Key and Secret Rotation
│
▼
Negative Security Testing
Interview Quick Revision
| Concept | Purpose |
|---|---|
| Jakarta Security | Standard application security API |
| Authentication | Verify caller identity |
| Authorization | Verify caller permission |
| IdentityStore | Validate credentials and groups |
| IdentityStoreHandler | Coordinate identity stores |
| HttpAuthenticationMechanism | Authenticate HTTP requests |
| SecurityContext | Access current caller identity |
| Principal | Authenticated caller |
| Role | Group of permissions |
@RolesAllowed |
Restrict by role |
@PermitAll |
Allow all callers |
@DenyAll |
Deny all callers |
| JWT | Signed token format |
| RBAC | Role-based access control |
| Fine-Grained Authorization | Resource and policy checks |
Key Takeaways
- Jakarta Security provides a standardized authentication and identity-store model for Jakarta EE applications.
- Authentication verifies who the caller is.
- Authorization verifies what the caller may do.
IdentityStorevalidates credentials and provides caller groups.IdentityStoreHandlercoordinates one or more identity stores.HttpAuthenticationMechanismhandles HTTP credential extraction and login communication with the container.SecurityContextexposes the authenticated principal and role information.- Role-based access control provides coarse-grained authorization.
- Fine-grained ownership, tenant, region, amount, and workflow checks are often required in addition to roles.
@RolesAllowed,@PermitAll, and@DenyAllprovide declarative method-level access control.- Form authentication requires HTTPS, secure sessions, CSRF protection, and session-ID regeneration.
- Basic Authentication sends reusable credentials and must never be used without TLS.
- JWT authentication requires signature, issuer, audience, expiration, algorithm, and claim validation.
- JWT payloads are signed but not automatically encrypted.
- Access tokens, ID tokens, and refresh tokens serve different purposes.
- Passwords must be stored with a dedicated password-hashing algorithm such as Argon2, bcrypt, scrypt, or PBKDF2.
- CORS is not an authentication or authorization mechanism.
- CSRF protection is especially important for cookie-based authentication.
- Secure cookies require
Secure,HttpOnly, and appropriateSameSitesettings. - Secrets, keys, and client credentials should be stored in a secure secret-management platform.
- Service-to-service authentication should use scoped, short-lived credentials where possible.
- Security-sensitive actions should produce structured audit events.
- Production security requires defense in depth, threat modeling, negative testing, monitoring, key rotation, and incident-response planning.