Skip to main content
Planned feature: This page describes the intended JWT authentication implementation. The current codebase includes Spring Security as a dependency but does not yet implement authentication endpoints or JWT token generation.

Overview

OrgStack will use JWT (JSON Web Tokens) for stateless authentication. When users log in, the server will issue a signed token containing their identity and organization membership. Users will include this token in subsequent requests to prove their identity.

Authentication flow

1

User submits credentials

You send your email and password to the /auth/login endpoint.
2

Server validates credentials

Spring Security’s authentication manager verifies your credentials against the database. Passwords are hashed using BCrypt.
3

JWT token generation

If credentials are valid, the server generates a JWT containing your user ID, organization ID, and roles.
4

Client stores token

The Angular frontend stores the JWT in memory (or httpOnly cookie for enhanced security).
5

Token included in requests

All subsequent API requests include the JWT in the Authorization: Bearer <token> header.
6

Server validates token

Spring Security’s JWT filter validates the token signature and extracts the authenticated principal.

Spring Security configuration

OrgStack integrates Spring Security 6.x (part of Spring Boot 4.0.3) with JWT-based authentication:
pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
Spring Security provides comprehensive security features including authentication, authorization, CSRF protection, and secure headers out of the box.

JWT token structure

A typical OrgStack JWT contains these claims:
{
  "sub": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "organizationId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "email": "[email protected]",
  "roles": ["ADMIN", "USER"],
  "iat": 1709251200,
  "exp": 1709337600
}

Token claims explained

  • sub: Subject - your user UUID from the database
  • organizationId: The tenant/organization you belong to (critical for multi-tenancy)
  • email: Your email address for display purposes
  • roles: Your roles within the organization for authorization
  • iat: Issued at timestamp (Unix epoch)
  • exp: Expiration timestamp (typically 24 hours)
The JWT signature ensures the token cannot be tampered with. Never store sensitive data like passwords in JWT claims - they are base64 encoded but not encrypted.

Password security

Passwords in OrgStack are secured using industry-standard practices:

BCrypt hashing

Passwords are hashed with BCrypt, which includes automatic salting and configurable cost factor.

Never logged

Password fields are excluded from all logging and serialization.

One-way only

Passwords cannot be decrypted - only validated against the stored hash.

Secure transport

Always transmitted over HTTPS in production environments.

Security filter chain

Spring Security’s filter chain processes every request:
Request

[CORS Filter]

[JWT Authentication Filter]
  → Extract token from Authorization header
  → Validate token signature
  → Parse claims
  → Create Authentication object

[Authorization Filter]
  → Check if user has required roles
  → Verify tenant context matches

[Controller]

Token validation

The JWT filter performs these validations on every request:
Validates that the token was signed by the server using the secret key. This prevents token forgery.
Ensures the token hasn’t expired. Expired tokens are rejected with 401 Unauthorized.
Verifies that required claims (sub, organizationId) are present and have valid formats (UUIDs).
Optionally queries the database to confirm the user still exists and is active (can be cached).

Session management

OrgStack uses stateless authentication:
  • No server-side sessions: The JWT contains all necessary information
  • Horizontal scalability: Any server instance can validate any token
  • Logout handling: Tokens cannot be invalidated server-side (use short expiration times)
  • Refresh tokens: Longer-lived tokens can be used to obtain new access tokens
For enhanced security, consider implementing token revocation using a Redis blacklist for logged-out tokens.

Entity auditing

Spring Data JPA automatically tracks who created and modified entities:
JpaConfig.java
package com.orgstack.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing
public class JpaConfig {
}
When combined with @CreatedDate and @LastModifiedDate annotations in BaseEntity, this provides automatic audit trails:
BaseEntity.java
@CreatedDate
@Column(nullable = false, updatable = false)
private Instant createdAt;

@LastModifiedDate
@Column(nullable = false)
private Instant updatedAt;
You can extend auditing to track createdBy and lastModifiedBy by implementing Spring Security’s AuditorAware interface.

Public endpoints

Certain endpoints don’t require authentication:
  • /auth/login - Login endpoint
  • /auth/register - User registration
  • /health - Health check for monitoring
  • /actuator/** - Spring Boot Actuator endpoints (should be secured in production)

CORS configuration

For the Angular frontend to communicate with the Spring Boot backend, CORS (Cross-Origin Resource Sharing) must be configured:
@Configuration
public class SecurityConfig {
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("http://localhost:4200"));
        configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
        configuration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
        return source;
    }
}

Best practices

1

Use HTTPS in production

Always use TLS/SSL to encrypt tokens in transit. Never send JWTs over plain HTTP.
2

Short token lifetimes

Keep access token expiration short (15 minutes to 1 hour). Use refresh tokens for longer sessions.
3

Validate all claims

Don’t trust token claims blindly. Always validate UUIDs are properly formatted and reference existing entities.
4

Handle token expiration gracefully

Implement automatic token refresh in your frontend to provide seamless user experience.

Testing authentication

Spring Security provides test utilities:
@SpringBootTest
@AutoConfigureMockMvc
class SecurityTests {
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    @WithMockUser(roles = "ADMIN")
    void testAdminEndpoint() throws Exception {
        mockMvc.perform(get("/api/admin/users"))
            .andExpect(status().isOk());
    }
}

Next steps

Authorization

Learn about role-based access control

Multi-tenancy

Understand how tenant context flows through authentication

Build docs developers (and LLMs) love