false, 'error' => 'malformed_token' ]; } $payload = self::b64u_decode( $parts[0] ); if ( $payload === null || ! self::verify( $payload, $parts[1], $base_pub ) ) { return [ 'ok' => false, 'error' => 'bad_signature' ]; } $c = json_decode( $payload, true ); if ( ! is_array( $c ) ) { return [ 'ok' => false, 'error' => 'malformed_token' ]; } if ( ( $c['v'] ?? null ) !== 1 ) { return [ 'ok' => false, 'error' => 'unsupported_version' ]; } if ( ! hash_equals( $base_key_id, (string) ( $c['iss'] ?? '' ) ) ) { return [ 'ok' => false, 'error' => 'wrong_issuer' ]; } if ( ! hash_equals( $site_id, (string) ( $c['aud'] ?? '' ) ) || $site_id === '' ) { return [ 'ok' => false, 'error' => 'wrong_audience' ]; } $iat = isset( $c['iat'] ) ? (int) $c['iat'] : 0; $exp = isset( $c['expires_at'] ) ? (int) $c['expires_at'] : 0; if ( $iat <= 0 || $exp <= 0 ) { return [ 'ok' => false, 'error' => 'malformed_token' ]; } if ( $exp <= $now ) { return [ 'ok' => false, 'error' => 'expired' ]; } if ( $exp - $iat > self::MAX_TOKEN_LIFETIME || $iat > $now + self::MAX_SKEW ) { return [ 'ok' => false, 'error' => 'lifetime_too_long' ]; } $nonce = (string) ( $c['nonce'] ?? '' ); if ( strlen( $nonce ) < 8 || strlen( $nonce ) > 64 ) { return [ 'ok' => false, 'error' => 'bad_nonce' ]; } if ( ! isset( $c['allowed_scopes'] ) || ! is_array( $c['allowed_scopes'] ) ) { return [ 'ok' => false, 'error' => 'malformed_token' ]; } foreach ( $c['allowed_scopes'] as $s ) { if ( ! is_string( $s ) || $s === '' ) { return [ 'ok' => false, 'error' => 'malformed_token' ]; } } return [ 'ok' => true, 'claims' => $c ]; } }