Before I answer, I should preface by saying that I think this is an opinion-based question that might generate better discussion on Sitecore Community Slack. Having said that, my opinion is below.
If you have a highly scaled solution (which habitat is meant to be an example of a scalable solution) then you might have more than one authentication feature with unique tracking logic or you may have project-specific tracking logic for specific sites or tenants. In these cases, the application still requires that when a user authenticates his contact is identified. We can say this because the feature calls an extensible (important for scalability) pipeline in the Foundation layer, which then calls a method implemented in the feature layer (so that it can have different logic for each implementing feature) that performs the contact identification.
The idea here is that not only does this make the solution more extensible and scalable, but if you were to start a new project you could take the foundation layer with you and likely some of the features and reuse it as a starting point. Of course, if you reuse it in a far simpler solution then, yes, you will likely have logic that is far more complicated than what you would have otherwise needed, but the trade-off is that you don't actually have to write any of it from scratch. All you would have to do is write the implementing logic that identifies the contact, which is required for the code to run so it's even self-documenting for developers of all skill-levels. In other words, while it may be more complicated than what you need it will work "every time" (grain of salt) and will require less coding and documentation (maybe even has reusable documentation), and thus will be cheaper than writing it from scratch.
Update: What is the benefit of a pipeline in this scenario?
Pipelines are great because they're extensible. You can add an implementing processor in any layer (of course, put it in the layer most appropriate for your use-case; usually in the foundation or feature layers), and can patch it in from that layer as well. This means that processors are one of those wonderful tools that have minimal risk of violating the directions of your dependencies, and if you ever need to change or extend the behavior later you can do so without actually removing or modifying the code that's already been deployed, but rather you can just add a new DLL to it. I could talk for ages about the benefits of a pipeline in most any scenario.