While you can definitely manually pipe all of the pieces together and have a functioning system, it's significantly easier, and likely more secure, to use the battle-tested auth library of a framework.
One could also use the builtin language functionality and external packages to write custom crypto, and I think we'd both agree that that's a bad idea. I'd argue that it's the same for authentication in general.