Easy Full Stack Authentication and Login in the Style of Spring
Three requests leave your app just as its access token expires. If each refreshes independently, the first exchange can invalidate the refresh token the other two are about to use. A login feature becomes a race between requests. What is Codename One? Codename One is an open-source framework for building native iOS, Android, desktop, and web apps from a single Java or Kotlin codebase. Learn more…
When a user's access token expires, three requests leave the application simultaneously. If each request refreshes independently, the first exchange might invalidate the refresh token used by the other two requests. This creates a race condition in the login feature. Codename One is an open-source framework that allows developers to build native iOS, Android, desktop, and web applications from a single Java or Kotlin codebase.
This week's security update integrates the Codename One client and backend around token renewals and refreshes. The client can coordinate token renewals, while the server rotates the tokens, and tests verify the outcome after a real request is denied. The access rule should be placed next to the route. The backend utilizes Spring-style security chains under com.codename1.backend.security. These chains decide which requests to handle, authenticate them, and authorize access.
The example security configuration protects an API using JWT scopes. The @Bean @Order(1) SecurityFilterChain api (HttpSecurity http) { ... } section configures the security rules. It authorizes requests based on JWT scopes, enables session management in a stateless manner, and configures OAuth2 resource server with JWT validation. The issuer URI and audience are configured using cn1.security.oauth2.resourceserver.jwt.issuer-uri and cn1.security.oauth2.resourceserver.jwt.audiences, respectively.
A backend without a SecurityFilterChain bean has no security layer. Adding a dependency alone does not secure the routes. Stateless chains also lack CSRF protection unless explicitly configured. Method rules like @PreAuthorize are compiled into the method, allowing checks on self-calls and private methods. The expression language supports a subset of ACLs, @PostAuthorize, and arbitrary expression evaluation.
The client registers as a public OAuth client with a specific redirect URI and PKCE. After configuring OidcClient, install an authorizer for the API base URL. The OidcRequestAuthorizer matches the scheme, host, and port, then the entire path. It checks whether a signed-in listener should be triggered and handles session management. If a token-bearing request receives a 401 error, the authorizer can refresh the token and retry the request. If the refresh fails, the session is cleared, and a sign-in listener is called.
The backend supports various authentication methods, including form login, HTTP Basic, API keys, JWT resource servers, and OAuth login. Multi-factor authentication (MFA) options include TOTP and recovery codes, while passkey endpoints use WebAuthn. These mechanisms have separate configurations and do not share resources, such as in-memory token repositories or rate limiters. Ensure that refresh tokens and one-use codes are consumed atomically to prevent sharing between instances.
The packaged server links all the mechanisms used by the chains. A token-verifying API does not need login pages or a password store, thanks to explicit configuration and dead-code removal. However, this does not reduce the importance of reviewing the security rules enabled. Test the failure scenario after a successful login using the HelloCodenameOne backend.
The BackendTokenRefreshTest replaces the access token with an invalid one and verifies that the generated client receives a successful response after renewal, that the refresh token rotates, and that reusing a spent refresh token ends the session. This test ensures the system handles token failures correctly.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.