Barca struggled to create first-half chances after Sevilla loanee Luuk de Jong thought he'd put the visitors ahead in the eighth minute with a fine header, but after a lengthy video assistant referee (VAR) check, Gavi, who provided the cross, was ruled offside by the finest of margins.
De Jong had a second opportunity in the 57th minute that would count, rising to hit the target again, this time from a pinpoint Dani Alves cross, and nodding past a helpless Luis Maximiano to put Barca in front in the second half, the Dutchman's second goal in as many weeks for the Blaugrana.
Gavi's late sending off put Xavi's side under pressure and with time running out, Puertas volleyed past Marc-Andre ter Stegen to deny Barca all three points.
While the Catalan giant has lost just once in 10 La Liga games, it sits sixth in the table in the battle to secure a UEFA Champions League spot.