After the two sides played out a 1-1 draw in Sunday's semi-final second leg following their 1-1 stalemate in the first encounter in Garoua before the international break, Ahmed Fathi scored what turned out to be winner when the tie was settled in a tense shoot-out.
The spot-kicks did not get off to a good start for Al Ahly, though, as Mohamed Aboutrika missed their first penalty.
The experienced midfielder was the only player to miss for the hosts, however, as Coton duo Kada Yougouda and Jacques Haman failed to find the net, making Fathi's kick the winner.
Al Ahly had earlier took the lead after three minutes in normal time as Sayed Moawad whipped in a good cross from the left that Abdallah El-Said met with a header, directing the ball past Loic Feudjou in the visitors' goal.
Walid Soliman had a good opportunity to double their lead 20 minutes later, but his half-volley from a tight angle missed the target after finding space in the area.
Coton created their first chance in the 34th minute as Emmanuel Mbongo held off his marker in the area and shot, but Sherif Ekramy got down to make the block.
Al Ahly kept their lead going into the break, but Coton drew level in the 65th minute.
After a cross from the left was not dealt with by Sherif Abdel-Fadil, Yougouda knocked the ball into the net from close range, bringing the aggregate score to 2-2.
The hosts piled on the pressure in the final 20 minutes, but they struggled to create goalscoring opportunities and Coton held on until full-time, meaning the matter had to be settled on penalties.
Al Ahly got off to a poor start in the shoot-out as the usually-reliable Aboutrika missed, but Coton's Yougouda soon wasted his own effort.
Fathi kept his cool to edge Al Ahly 7-6 ahead before Haman missed as the home side set up a final against Orlando Pirates.
Get the best features, fun and footballing frolics straight to your inbox every week.
Thank you for signing up to Four Four Two. You will receive a verification email shortly.
There was a problem. Please refresh the page and try again.