@@ -358,6 +358,7 @@ impl SupabaseAuthConfig {
358358 fn validate_token ( & self , token : & str ) -> Result < SupabaseClaims , jsonwebtoken:: errors:: Error > {
359359 let mut validation = Validation :: new ( Algorithm :: HS256 ) ;
360360 validation. validate_exp = true ;
361+ validation. validate_nbf = true ;
361362 validation. validate_aud = true ;
362363 validation. leeway = 0 ;
363364 validation. set_required_spec_claims ( & [ "exp" , "iss" , "aud" ] ) ;
@@ -677,6 +678,27 @@ mod tests {
677678 token_with_audience ( exp_offset_seconds, Some ( json ! ( "authenticated" ) ) )
678679 }
679680
681+ fn token_with_nbf_offset ( nbf_offset_seconds : i64 ) -> String {
682+ let now = std:: time:: SystemTime :: now ( )
683+ . duration_since ( std:: time:: UNIX_EPOCH )
684+ . expect ( "unix epoch" )
685+ . as_secs ( ) as i64 ;
686+ let claims = json ! ( {
687+ "iss" : "https://example.supabase.co/auth/v1" ,
688+ "sub" : "operator-123" ,
689+ "aud" : "authenticated" ,
690+ "exp" : now + 300 ,
691+ "nbf" : now + nbf_offset_seconds,
692+ } ) ;
693+
694+ encode (
695+ & Header :: new ( Algorithm :: HS256 ) ,
696+ & claims,
697+ & EncodingKey :: from_secret ( b"test-only-high-entropy-secret-material" ) ,
698+ )
699+ . expect ( "encode test jwt" )
700+ }
701+
680702 fn test_router ( ) -> Router {
681703 async fn ok_handler ( ) -> Json < Value > {
682704 Json ( json ! ( { "ok" : true } ) )
@@ -767,6 +789,26 @@ mod tests {
767789 assert_eq ! ( response. status( ) , StatusCode :: UNAUTHORIZED ) ;
768790 }
769791
792+ #[ tokio:: test]
793+ async fn token_with_future_nbf_returns_401 ( ) {
794+ let response = test_router ( )
795+ . oneshot (
796+ Request :: builder ( )
797+ . method ( Method :: GET )
798+ . uri ( "/api/observability/snapshot" )
799+ . header (
800+ AUTHORIZATION ,
801+ format ! ( "Bearer {}" , token_with_nbf_offset( 60 ) ) ,
802+ )
803+ . body ( Body :: empty ( ) )
804+ . expect ( "request" ) ,
805+ )
806+ . await
807+ . expect ( "response" ) ;
808+
809+ assert_eq ! ( response. status( ) , StatusCode :: UNAUTHORIZED ) ;
810+ }
811+
770812 #[ tokio:: test]
771813 async fn token_without_audience_returns_401 ( ) {
772814 let response = test_router ( )
0 commit comments