1- using CodeBeam . UltimateAuth . Server . Auth ;
1+ using CodeBeam . UltimateAuth . Core ;
2+ using CodeBeam . UltimateAuth . Core . Domain ;
3+ using CodeBeam . UltimateAuth . Server . Auth ;
24using CodeBeam . UltimateAuth . Server . Options ;
35using Microsoft . AspNetCore . Http ;
46
57namespace CodeBeam . UltimateAuth . Server . Cookies ;
68
79internal sealed class DefaultUAuthCookiePolicyBuilder : IUAuthCookiePolicyBuilder
810{
9- public CookieOptions Build ( CredentialResponseOptions response , AuthFlowContext context , TimeSpan ? logicalLifetime )
11+ public CookieOptions Build ( CredentialResponseOptions response , AuthFlowContext context , CredentialKind kind )
1012 {
1113 if ( response . Cookie is null )
1214 throw new InvalidOperationException ( "Cookie policy requested but Cookie options are null." ) ;
@@ -18,11 +20,11 @@ public CookieOptions Build(CredentialResponseOptions response, AuthFlowContext c
1820 HttpOnly = src . HttpOnly ,
1921 Secure = src . SecurePolicy == CookieSecurePolicy . Always ,
2022 Path = src . Path ,
21- Domain = src . Domain
23+ Domain = src . Domain ,
24+ SameSite = ResolveSameSite ( src , context )
2225 } ;
2326
24- options . SameSite = ResolveSameSite ( src , context ) ;
25- ApplyLifetime ( options , src , logicalLifetime ) ;
27+ ApplyLifetime ( options , src , context , kind ) ;
2628
2729 return options ;
2830 }
@@ -41,30 +43,51 @@ private static SameSiteMode ResolveSameSite(UAuthCookieOptions cookie, AuthFlowC
4143 } ;
4244 }
4345
44- private static void ApplyLifetime ( CookieOptions target , UAuthCookieOptions src , TimeSpan ? logicalLifetime )
46+ private static void ApplyLifetime ( CookieOptions target , UAuthCookieOptions src , AuthFlowContext context , CredentialKind kind )
4547 {
4648 var buffer = src . Lifetime . IdleBuffer ?? TimeSpan . Zero ;
47- TimeSpan ? baseLifetime = null ;
49+ var baseLifetime = ResolveBaseLifetime ( context , kind , src ) ;
4850
49- // 1️⃣ Hard MaxAge override (base)
50- if ( src . MaxAge is not null )
51- {
52- baseLifetime = src . MaxAge ;
53- }
54- // 2️⃣ Absolute lifetime override (base)
55- else if ( src . Lifetime . AbsoluteLifetimeOverride is not null )
51+ if ( baseLifetime is not null )
5652 {
57- baseLifetime = src . Lifetime . AbsoluteLifetimeOverride ;
53+ target . MaxAge = baseLifetime . Value + buffer ;
5854 }
59- // 3️⃣ Logical lifetime (effective)
60- else if ( logicalLifetime is not null )
55+ }
56+
57+ private static TimeSpan ? ResolveBaseLifetime ( AuthFlowContext context , CredentialKind kind , UAuthCookieOptions src )
58+ {
59+ if ( src . MaxAge is not null )
60+ return src . MaxAge ;
61+
62+ if ( src . Lifetime . AbsoluteLifetimeOverride is not null )
63+ return src . Lifetime . AbsoluteLifetimeOverride ;
64+
65+ return kind switch
6166 {
62- baseLifetime = logicalLifetime ;
63- }
67+ CredentialKind . Session => ResolveSessionLifetime ( context ) ,
68+ CredentialKind . RefreshToken => context . EffectiveOptions . Options . Tokens . RefreshTokenLifetime ,
69+ CredentialKind . AccessToken => context . EffectiveOptions . Options . Tokens . AccessTokenLifetime ,
70+ _ => null
71+ } ;
72+ }
6473
65- if ( baseLifetime is not null )
74+ private static TimeSpan ? ResolveSessionLifetime ( AuthFlowContext context )
75+ {
76+ var sessionIdle = context . EffectiveOptions . Options . Session . IdleTimeout ;
77+ var refresh = context . EffectiveOptions . Options . Tokens . RefreshTokenLifetime ;
78+
79+ return context . EffectiveMode switch
6680 {
67- target . MaxAge = baseLifetime . Value + buffer ;
68- }
81+ UAuthMode . PureOpaque => sessionIdle ,
82+ UAuthMode . Hybrid => Max ( sessionIdle , refresh ) ,
83+ _ => sessionIdle
84+ } ;
85+ }
86+
87+ private static TimeSpan ? Max ( TimeSpan ? a , TimeSpan ? b )
88+ {
89+ if ( a is null ) return b ;
90+ if ( b is null ) return a ;
91+ return a > b ? a : b ;
6992 }
7093}
0 commit comments