@@ -32,7 +32,7 @@ function ms_b64u_json(array $a): string { return ms_b64u(json_encode($a, JSON_UN
3232 * Order of precedence:
3333 * 1) SMULTI_SSO_SECRET from environment (recommended: same across domains).
3434 * 2) If absent — read/write core/storage/ms_sso/secret.key (shared FS).
35- * 3) Derive the final key by HMAC with SESSION_COOKIE_NAME as "info"/salt .
35+ * 3) Normalize the final key to 32 raw bytes (SHA-256) .
3636 *
3737 * @return string Raw bytes (string) to be used as HMAC key.
3838 */
@@ -42,6 +42,9 @@ function ms_sso_secret(): string {
4242 if ($ sec ) return $ sec ;
4343
4444 $ base = getenv ('SMULTI_SSO_SECRET ' );
45+ if ((!$ base || $ base === '' ) && function_exists ('env ' )) {
46+ $ base = env ('SMULTI_SSO_SECRET ' );
47+ }
4548 if (!$ base || strlen ($ base ) < 32 ) {
4649 $ dir = rtrim (EVO_CORE_PATH ?? __DIR__ , '/ ' ) . '/storage/ms_sso ' ;
4750 $ file = $ dir . '/secret.key ' ;
@@ -54,10 +57,10 @@ function ms_sso_secret(): string {
5457 }
5558 }
5659
57- $ cookieName = defined ( ' SESSION_COOKIE_NAME ' ) ? SESSION_COOKIE_NAME : session_name ();
58- // HKDF-like derivation: bind to cookie name (makes cross-install reuse safer).
59- $ derived = hash_hmac ( ' sha256 ' , $ cookieName , $ base , true );
60- return $ sec = $ derived ;
60+ // Important: do not bind the signing key to SESSION_COOKIE_NAME.
61+ // In multi-domain setups cookie names often differ between domains,
62+ // which would make SSO tokens unverifiable and produce "Invalid/expired".
63+ return $ sec = hash ( ' sha256 ' , ( string ) $ base , true ) ;
6164 }
6265}
6366
@@ -86,16 +89,17 @@ function ms_sso_token_make(array $claims, int $ttl = 180): string {
8689 * @return array|null Payload if valid; null otherwise
8790 */
8891if (!function_exists ('ms_sso_token_parse ' )) {
89- function ms_sso_token_parse (string $ jwt ): ?array {
90- if (!preg_match ('~^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+$~ ' , $ jwt )) return null ;
92+ function ms_sso_token_parse (string $ jwt , ?string &$ err = null ): ?array {
93+ $ err = null ;
94+ if (!preg_match ('~^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+$~ ' , $ jwt )) { $ err = 'format ' ; return null ; }
9195 [$ h , $ p , $ s ] = explode ('. ' , $ jwt , 3 );
9296 $ calc = ms_b64u (hash_hmac ('sha256 ' , "$ h. $ p " , ms_sso_secret (), true ));
93- if (!hash_equals ($ calc , $ s )) return null ;
97+ if (!hash_equals ($ calc , $ s )) { $ err = ' signature ' ; return null ; }
9498 $ payload = json_decode (base64_decode (strtr ($ p , '-_ ' , '+/ ' )), true );
95- if (!$ payload || !is_array ($ payload )) return null ;
99+ if (!$ payload || !is_array ($ payload )) { $ err = ' payload ' ; return null ; }
96100 $ now = time ();
97- if (isset ($ payload ['nbf ' ]) && $ payload ['nbf ' ] > $ now ) return null ;
98- if (isset ($ payload ['exp ' ]) && $ payload ['exp ' ] < $ now ) return null ;
101+ if (isset ($ payload ['nbf ' ]) && $ payload ['nbf ' ] > $ now ) { $ err = ' nbf ' ; return null ; }
102+ if (isset ($ payload ['exp ' ]) && $ payload ['exp ' ] < $ now ) { $ err = ' exp ' ; return null ; }
99103 return $ payload ;
100104 }
101105}
0 commit comments