contexa-identity

Authentication

DSL options and code examples for each authentication method. Detailed reference for authentication methods configured via .form(), .rest(), .ott(), .passkey() in the Identity DSL.

Overview

Contexa Identity provides four authentication methods. Each method creates an independent SecurityFilterChain, and priority is controlled via order().

Authentication MethodDSL MethodDefault OrderPurpose
Form Login.form()100Traditional web form login (server-rendered)
REST API.rest()200JSON-based API authentication (SPA, mobile)
One-Time Token.ott()300Magic Link / email authentication
WebAuthn / Passkey.passkey()400Biometric authentication / hardware keys

All authentication methods support access to the full Spring Security API via rawHttp(), and support common options (order, CSRF, CORS, headers, logout, etc.).

For how to use these authentication methods with MFA (Multi-Factor Authentication), see the Adaptive MFA documentation. URLs, adapters, and state management behave differently in single authentication vs. MFA flows.

Form Login

Traditional web form-based login. Configures Spring Security's formLogin() via the DSL. Default order is 100.

All Options

MethodTypeDefaultDescription
loginPage(String)StringUnset in single-auth mode; MFA builder preloads the primary login pageLogin page URL
usernameParameter(String)String"username"Username parameter name
passwordParameter(String)String"password"Password parameter name
loginProcessingUrl(String)StringAuthUrlProvider.getSingleFormLoginProcessing()Login processing URL
defaultSuccessUrl(String)StringRedirect URL after successful login
defaultSuccessUrl(String, boolean)String, booleanSuccess URL + alwaysUse flag
failureUrl(String)StringRedirect URL on login failure
permitAll()falseEnable unauthenticated access to the configured login page
successHandler(PlatformAuthenticationSuccessHandler)HandlerAuto-selectedCustom success handler
failureHandler(PlatformAuthenticationFailureHandler)HandlerAuto-selectedCustom failure handler
securityContextRepository(SecurityContextRepository)RepositoryAuto-selected by state typeSecurity context repository
rawFormLogin(SafeHttpFormLoginCustomizer)CustomizerDirect customization within formLogin()
rawHttp(SafeHttpCustomizer<HttpSecurity>)CustomizerFull Spring Security API access (cumulative)
order(int)int100Filter chain priority
asep(Customizer<FormAsepAttributes>)CustomizerASEP annotation attribute configuration

Basic Configuration

registry
    .form(form -> form
        .loginPage("/login")
        .defaultSuccessUrl("/home")
        .failureUrl("/login?error")
        .permitAll()
    )
    .session(Customizer.withDefaults())
    .build();

Custom Handlers

registry
    .form(form -> form
        .loginPage("/login")
        .usernameParameter("email")
        .passwordParameter("passwd")
        .successHandler(customSuccessHandler)
        .failureHandler(customFailureHandler)
    )
    .session(Customizer.withDefaults())
    .build();

Advanced Configuration (rawHttp + rawFormLogin)

registry
    .form(form -> form
        .order(20)
        .loginPage("/admin/login")
        .rawFormLogin(formLogin -> formLogin
            .usernameParameter("admin_user")
            .passwordParameter("admin_pass"))
        .rawHttp(http -> http
            .securityMatcher("/admin/**")
            .sessionManagement(session -> session
                .maximumSessions(1)
                .maxSessionsPreventsLogin(true)))
    )
    .session(Customizer.withDefaults())
    .build();
rawFormLogin() vs rawHttp()
rawFormLogin() only customizes the internals of HttpSecurity.formLogin(). rawHttp() provides access to the full Spring Security API (sessionManagement, securityMatcher, custom filter registration, etc.). Both methods support cumulative invocations.

REST API Authentication

JSON-based REST API authentication. Authenticates via JSON payloads from frontend clients such as SPAs and mobile apps. Default order is 200.

All Options

MethodTypeDefaultDescription
loginProcessingUrl(String)StringAuthUrlProvider.getSingleRestLoginProcessing()REST login processing URL
defaultSuccessUrl(String)StringRedirect URL after success
defaultSuccessUrl(String, boolean)String, booleanSuccess URL + alwaysUse flag
failureUrl(String)StringRedirect URL on failure
successHandler(PlatformAuthenticationSuccessHandler)HandlerAuto-selectedCustom success handler
failureHandler(PlatformAuthenticationFailureHandler)HandlerAuto-selectedCustom failure handler
securityContextRepository(SecurityContextRepository)RepositoryAuto-selected by state typeSecurity context repository
rawHttp(SafeHttpCustomizer<HttpSecurity>)CustomizerFull Spring Security API access (cumulative)
order(int)int200Filter chain priority
asep(Customizer<RestAsepAttributes>)CustomizerASEP annotation attribute configuration

Basic Configuration

registry
    .rest(rest -> rest
        .loginProcessingUrl("/api/auth/login")
    )
    .oauth2(Customizer.withDefaults())
    .build();

Stateless API Configuration (rawHttp)

registry
    .rest(rest -> rest
        .order(50)
        .loginProcessingUrl("/api/auth")
        .rawHttp(http -> http
            .securityMatcher("/api/**")
            .sessionManagement(session ->
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)))
    )
    .oauth2(Customizer.withDefaults())
    .build();
REST + OAuth2 Combination
REST API authentication is typically combined with .oauth2() for stateless JWT-based operation. It can also be combined with .session(), but OAuth2 is recommended for API servers.

One-Time Token (Magic Link)

Authentication via a one-time token sent by email or SMS. Passwordless authentication using the Magic Link approach. Default order is 300.

All Options

MethodTypeDefaultDescription
tokenGeneratingUrl(String)StringToken generation request URL
defaultSubmitPageUrl(String)StringToken input page URL
parameter namesString"username" / "token"The current public OTT DSL keeps the default parameter names. Custom parameter names require lower-level option customization rather than dedicated DSL setters.
showDefaultSubmitPage(boolean)booleantrueWhether to display the default token submit page
tokenService(OneTimeTokenService)ServiceBean from the application contextToken generation/verification service implementation (required)
tokenGenerationSuccessHandler(OneTimeTokenGenerationSuccessHandler)HandlerToken generation success handler (e.g., email delivery)
loginProcessingUrl(String)StringAuthUrlProvider.getSingleOttLoginProcessing()Token verification processing URL
successHandler(PlatformAuthenticationSuccessHandler)HandlerAuto-selectedAuthentication success handler
failureHandler(PlatformAuthenticationFailureHandler)HandlerAuto-selectedAuthentication failure handler
rawHttp(SafeHttpCustomizer<HttpSecurity>)CustomizerFull Spring Security API access (cumulative)
order(int)int300Filter chain priority
asep(Customizer<OttAsepAttributes>)CustomizerASEP annotation attribute configuration

Basic Configuration

registry
    .ott(ott -> ott
        .tokenService(customTokenService)
        .tokenGenerationSuccessHandler(emailSendingHandler)
    )
    .session(Customizer.withDefaults())
    .build();

Custom Pages + Email Delivery Handler

registry
    .ott(ott -> ott
        .tokenGeneratingUrl("/auth/magic-link/request")
        .defaultSubmitPageUrl("/auth/magic-link/verify")
        // The public OTT DSL keeps the default token parameter name: "token"
        .showDefaultSubmitPage(false)
        .tokenService(jpaOneTimeTokenService)
        .tokenGenerationSuccessHandler((request, response, token) -> {
            String email = request.getParameter("username");
            emailService.sendMagicLink(email, token.getTokenValue());
            response.sendRedirect("/auth/magic-link/sent");
        })
    )
    .session(Customizer.withDefaults())
    .build();

WebAuthn / Passkey

FIDO2 WebAuthn-based biometric and hardware security key authentication. The most secure form of passwordless authentication. Default order is 400.

All Options

MethodTypeDefaultDescription
rpName(String)String"contexa-identity"Relying Party name (displayed to users)
rpId(String)String"localhost"Relying Party ID (domain)
allowedOrigins(Set<String>)Set<String>["http://localhost:${server.port}"] fallback when no explicit origins are configuredAllowed origins list
allowedOrigins(String...)String...Allowed origins (varargs)
assertionOptionsEndpoint(String)StringAuthUrlProvider.getSinglePasskeyAssertionOptions()Assertion options endpoint
loginProcessingUrl(String)StringAuthUrlProvider.getSinglePasskeyLoginProcessing()Authentication processing URL
successHandler(PlatformAuthenticationSuccessHandler)HandlerAuto-selectedAuthentication success handler
failureHandler(PlatformAuthenticationFailureHandler)HandlerAuto-selectedAuthentication failure handler
rawHttp(SafeHttpCustomizer<HttpSecurity>)CustomizerFull Spring Security API access (cumulative)
order(int)int400Filter chain priority
asep(Customizer<PasskeyAsepAttributes>)CustomizerASEP annotation attribute configuration

Basic Configuration

registry
    .passkey(passkey -> passkey
        .rpName("My Application")
        .rpId("example.com")
        .allowedOrigins("https://example.com")
    )
    .session(Customizer.withDefaults())
    .build();

Passkey Registration Flow

Passkey registration proceeds in three steps. The server stores credentials through Spring Security's UserCredentialRepository.


  Client                         Server
    |                               |
    |  1. POST /webauthn/register   |
    |        /options               |
    |  ---------------------------> |
    |                               | PublicKeyCredentialCreationOptions
    |  <--------------------------- | (rpId, rpName, userId, challenge)
    |                               |
    |  2. navigator.credentials     |
    |        .create(options)       |
    |  [Browser WebAuthn API]       |
    |                               |
    |  3. POST /webauthn/register   |
    |  ---------------------------> |
    |  (AuthenticatorAttestation    | Verify + Store in
    |   Response)                   | UserCredentialRepository
    |                               |
    |  <--- 201 Created ----------- |

Passkey Management REST API

MethodURLDescription
POST/webauthn/register/optionsGenerate registration options (PublicKeyCredentialCreationOptions)
POST/webauthn/registerRegister credential (AuthenticatorAttestationResponse verification)
POST/webauthn/authenticate/optionsGenerate authentication challenge (assertionOptionsEndpoint)
DELETE/webauthn/register/{id}Delete credential

Single Authentication vs MFA Second Factor

Passkey uses completely different URLs, adapters, and state management for single authentication versus MFA second-factor authentication.

AspectSingle AuthenticationMFA Second Factor
Authentication URL/login/webauthn/login/mfa-webauthn
AdapterPasskeyAuthenticationAdapterMfaPasskeyAuthenticationAdapter
FilterSpring Security built-inMfaPasskeyAuthenticationFilter
State ManagementSecurityContextRepositoryMFA State Machine
DSL Configuration.passkey().mfa(m -> m.passkey())

Automatic Handler Resolution

When no custom handler is specified for an authentication method, the appropriate handler is automatically selected based on the authentication flow and state type.

Success / Failure Handler Selection Rules

FlowState TypeSuccess HandlerFailure Handler
Single AuthSessionSpring Security defaultSpring Security default
Single AuthOAuth2OAuth2SingleAuthSuccessHandlerOAuth2SingleAuthFailureHandler
MFA PrimaryAnyPrimaryAuthenticationSuccessHandlerUnifiedAuthenticationFailureHandler
MFA SubsequentAnyMfaFactorProcessingSuccessHandlerUnifiedAuthenticationFailureHandler

SecurityContextRepository Selection Rules

FlowPhaseRepository
Single AuthSessionHttpSessionSecurityContextRepository
Single AuthOAuth2NullSecurityContextRepository
MFAPrimary (not final)NullSecurityContextRepository
MFAFinal stepAuto-selected by state type
MFAIntermediate stepNullSecurityContextRepository

For custom handler implementation, refer to the Extension Points section in the Adaptive MFA documentation.