There's probably a cleaner solution, but for the time being, you can use:

    import bpy
    from math import radians
    from mathutils import Vector, Matrix
    
    obj = bpy.context.active_object
    mesh = obj.data
    
    
    def get_layers():
        """
        return: tuple of 20 booleans. True if layer is active layer,False if not
        Allows the mesh to be created on the active layer. There is only 1 active layer
        """
        active_layer = bpy.context.scene.active_layer
        layers = [False] * 20
        layers[active_layer] = True
        return tuple(layers)
    
    
    def create_light_at_face():
        """
        layers: tuple. 20 booleans where exaclty one boolen is True
        return: None
        creates an area light the has the same orientation as the normal at the center of each face
        """
        mat_world = obj.matrix_world
        up = Vector((0,0,1))
        
        for poly in mesh.polygons:
            co = mat_world * Vector(poly.center)
            
            forward = poly.normal.copy()
            forward.rotate(mat_world)
            right = forward.cross(up).normalized() # Vector.length closer to 1.0
            up = right.cross(forward)
        
            rot = Matrix((right, up, -forward)).transposed().normalized().to_4x4()
            mat = Matrix.Translation(co) * rot
        
            bpy.ops.object.lamp_add(type='AREA', view_align=False, location=co, layers=get_layers())
            # scale lamp up a little fo we can see the area
            bpy.context.object.data.size = 3
            bpy.context.object.matrix_world = mat
    
    create_light_at_face()

Also tried eulers, but did not work reliably (some lamps pointing inwards).

As ideasman_42, suggested, `to_track_quat()` can be used to do the job, too:

            quat = poly.normal.to_track_quat('-Z', 'Y')
            loc = Matrix.Translation(poly.center)
            mat = mat_world * loc * quat.to_matrix().to_4x4()
            bpy.context.object.matrix_world = mat

It's not much code less, but more understandable I hope.