Authentication & Authorization with Spring Security
Importance of Authentication and Authorization in Web Applications
Security is a critical aspect of any web application, ensuring that only authorized users can access specific resources. Spring Security provides a robust framework for implementing authentication and authorization in Java applications. This article will explore key security concepts, real-world analogies, implementation methods, and best practices for securing your Spring Boot application.
Understanding Authentication vs. Authorization
Real-World Analogy
- Authentication is like checking a passport at an airport. The immigration officer verifies your identity before allowing you entry.
- Authorization is like having different access levels at an airport. Even after authentication, only airline staff can access restricted areas.
Technical Explanation
- Authentication is the process of verifying a user’s identity. This is typically done using credentials such as a username and password, OAuth tokens, or biometric authentication.
- Authorization determines what actions and resources an authenticated user is allowed to access. It is enforced through role-based access control or permission-based policies.
User Registration/ Login Flow in Spring Boot with Spring Security
Steps:
- User registers via an API (e.g., /register).
- Password is encrypted before storing in the database.
- User logs in using credentials.
- JWT token is issued upon successful authentication.
Password Encryption Process
Spring Security uses BCrypt for encrypting passwords.
public class PasswordEncryptionExample {
public static void main(String[] args) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String rawPassword = "mySecurePassword";
String encodedPassword = encoder.encode(rawPassword);
System.out.println("Encoded Password: " + encodedPassword);
}
}
Steps:
- The user enters a password.
- The password is hashed using BCrypt.
- The hashed password is stored in the database.
Password Decryption
BCrypt does not provide decryption. Instead, it compares raw input with the stored hash:
boolean isPasswordMatch = encoder.matches(rawPassword, encodedPassword);
User Access with JWT Token
This sequence diagram represents how a user accesses a protected resource using JWT (JSON Web Token) authentication with Spring Security. Here’s a step-by-step breakdown:
Step-by-Step Process
- User Requests Access:
- Frontend Sends JWT Token to Backend:
- The Frontend includes the JWT token (previously received after login) in the request and sends it to the Backend server.
- Backend Validates JWT Token with Spring Security
- Spring Security Validates the Token
- Spring Security checks if the JWT is valid (e.g., not expired, properly signed, valid role and issued by a trusted authority).
6. Backend Requests the Protected Resource
7. Resource Returns the Requested Data
What is JWT?
JSON Web Token (JWT) is a self-contained token used for secure authentication.
How It Works:
1. User logs in and receives a JWT token.
2. Client sends JWT in HTTP headers (Authorization: Bearer <token>).
3. Backend verifies the token.
4. If the token is valid, access is granted.
Refresh Token vs. Access Token
Access Token
- Purpose: Used to authenticate API requests by granting access to protected resources.
- Lifetime: Short-lived (typically expires in minutes or hours).
- Storage: Can be stored in memory (client-side) or in secure HTTP-only cookies.
- Scope: Grants limited access to specific resources, and usually has fine-grained permissions.
- Security: If exposed, it can be used to impersonate the user until it expires.
Refresh Token
- Purpose: Used to obtain a new access token when the current one expires.
- Lifetime: Long-lived (usually expires in days or weeks).
- Storage: Stored securely, typically in HTTP-only cookies (client-side) or encrypted storage.
- Scope: Provides the ability to refresh the access token, without providing direct access to resources.
- Security: More sensitive than access tokens. If compromised, it can be used to generate new access tokens.
Best Practices for Handling Refresh and Access Tokens
- Use Secure Storage:
- Store access tokens in memory or secure HTTP-only cookies (to prevent XSS attacks).
- Store refresh tokens securely (e.g., HTTP-only cookies with SameSite and Secure flags).
2. Short-Lived Access Tokens:
- Access tokens should have a short expiration time (e.g., 15 minutes to 1 hour) to limit the window for attack if compromised.
3. Long-Lived Refresh Tokens:
- Refresh tokens can have a longer expiration time (e.g., days, weeks) since they’re only used for generating new access tokens.
4. Rotate Refresh Tokens:
- Use a strategy to rotate refresh tokens (i.e., issue a new refresh token along with each access token) to reduce the risk if a refresh token is compromised.
5. Revoke Refresh Tokens:
- Implement a way to revoke refresh tokens (e.g., logout or token blacklist) if a user logs out or if the refresh token is suspected of being compromised.
6. Validate Tokens:
- Regularly validate access tokens and check their expiration and scope.
- For refresh tokens, ensure they’re securely stored and only used when necessary.
7. Handle Token Expiration Gracefully:
- Implement mechanisms like silent authentication (background refresh) for seamless user experience without frequent logins.
8. Limit Token Permissions:
- Grant access tokens minimal permissions necessary for a task (principle of least privilege).
JWT Token Signature Verification Process
The signature verification process is a crucial security mechanism in JWT that ensures the token’s integrity and authenticity.
Signature Creation
- Base64URL encode the header
- Base64URL encode the payload
- Combine them with a period separator: header.payload
- Apply the cryptographic algorithm (specified in header) with the secret key
Verification Steps
- Server receives JWT token in the Authorization header
- Token is split into three parts: header, payload, and signature
- Server recreates the signature using the same algorithm and secret key
- Compares the received signature with the recreated one
If the signature is correct, the token is valid. If it’s incorrect, the token is rejected.
Common Security Issues
- Using weak secret keys
- Not validating the algorithm specified in header (algorithm stripping attack)
- Not checking token expiration
- Security Key Management and Protection
What is a Security Key?
A security key (or secret key) in JWT is a private string used to sign and verify tokens. It acts as a unique identifier that ensures only authorized parties can create and validate tokens.
Storage Best Practices
- Environment Variables: Store keys in environment variables, never in source code
- Key Management Systems (KMS): Use cloud KMS solutions like AWS KMS or Azure Key Vault
- Hardware Security Modules (HSM): For high-security requirements, use dedicated hardware devices
- Configuration Management: Use secure configuration management tools with encryption
Protecting Against Key Theft
- Key Rotation → Change security keys regularly to reduce risk if stolen.
- Access Control → Limit who can access and manage security keys.
- Monitoring → Set up alerts for unusual token activity.
- Encryption → Always store and send keys in a secure, encrypted format.
Recovery Plan
If a security key is compromised:
- Immediately rotate to new security keys
- Invalidate all existing tokens
- Force all users to re-authenticate
- Investigate the breach and implement additional security measures
Never store security keys in client-side code, version control systems, or unencrypted configuration files. Always follow the principle of least privilege when managing access to security keys.
Common HTTP Error Codes in Production
401 – Handling Unauthorized Access
- Meaning: The request requires user authentication.
- When it occurs: It is returned when the user has not authenticated or provided invalid credentials (e.g., missing or incorrect login information).
- Example: A user tries to access a resource without logging in, or their session has expired.
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends RuntimeException {
public UnauthorizedException(String message) {
super(message);
}
}
403 — Handling Forbidden Access
- Meaning: The server understands the request, but it refuses to authorize it.
- When it occurs: It occurs when the user is authenticated but does not have sufficient permissions to access the resource (e.g., their account lacks the required role or permission).
- Example: A logged-in user tries to access an admin-only page without being an admin.
@ResponseStatus(HttpStatus.FORBIDDEN)
public class ForbiddenException extends RuntimeException {
public ForbiddenException(String message) {
super(message);
}
}
Conclusion
Spring Security provides powerful tools for securing applications. By understanding authentication, authorization, password encryption, and JWT-based access control, you can build secure web applications efficiently.
Authentication & Authorization with Spring Security was originally published in Javarevisited on Medium, where people are continuing the conversation by highlighting and responding to this story.
This post first appeared on Read More