
Ask HN: How do you currently solve authentication? - scottmotte
There are a lot of different ways to do authentication these days. How do you currently solve for it?<p>Any tools you swear by? Anything you recommend? Anything you hate? Do you recommend writing it from scratch or using a framework or service?
======
kisamoto
Depends on the project:

Firebase Authentication[1] is an excellent easy add on for apps (both Web and
Mobile) that I want to get running quickly. It's free, scales, supports lots
of social auth providers and can take care of email verification etc.

When I'm building a website it really depends. Wordpress and Django have
excellent inbuilt authentication and authorization systems. Djangos can be
quickly expanded to support social providers with `django-allauth`[2]

For everything else I use KeyCloak[3] - Red Hats open source Identity
Provider/Single Sign On which supports oAuth2.0, OpenID Connect, SAML, themes
etc. Documentation and support is relatively good but can be quite
overwhelming especially if you're not used to the relevant standards (knowing
the different flows in oAuth2.0 and which one you want to use).

[Self plug]: I'm building a KeyCloak-as-a-Service for those who don't want
control of their authentication without the hassle of setting up their own
cluster. We're in closed Beta at the moment but if you're interested you can
search for "Tromsso keycloak"[4] and leave an email to be invited in.

[1]
[https://firebase.google.com/docs/auth/](https://firebase.google.com/docs/auth/)

[2] [https://github.com/pennersr/django-
allauth](https://github.com/pennersr/django-allauth)

[3] [https://keycloak.org/](https://keycloak.org/)

[4] [https://tromsso.com/](https://tromsso.com/)

------
nujabe
Firebase Authentication.

I can't say enough good things about this service as it has been a game
changer for me productivity wise.

-Supports most of the popular OAuth providers natively or you can add any custom OAuth system via custom tokens.

-SMS Auth, passwordless login (aka magic links)

-Excellent and well maintained client/server SDKs for most of the languages. Makes user management very convenient, including neat things like revoking tokens, cookie session management, linking accounts of users with multiple providers, RBAC via web tokens.

-Tight integration with Firestore. Can have fine grained security controls on which users can read/write what documents etc.

What takes the cake is Custom Tokens [1]. This is really useful for seamlessly
integrating with another authentication system. Would recommend anyone to take
a look if they're exploring an auth service.

[1] [https://firebase.google.com/docs/auth/admin/create-custom-
to...](https://firebase.google.com/docs/auth/admin/create-custom-tokens)

------
vbezhenar
I'm storing hashed password in the database. I'm writing POST http handler and
storing user info in the session information. I don't know why would I use
framework or even service, it's just few dozens of simple lines of code. I
don't use frameworks for simple things. I guess it might make sense when one
need to support login via Google, Facebook, etc, I'm working on enterprise
websites which don't need that.

~~~
XMPPwocky
Presumably checking user passwords for security is out of scope?

How do you mitigate credential stuffing attacks? Throttling per account?
Globally? By source IP?

A user leaves their company. How do you automatically deactivate their
account?

You're using password hashes. Cool. A secure password hash function, right?
Scrypt, argon2, maybe bcrypt? (MD5, SHA1, and SHA2 are not password hashes.)

You're comparing them in constant time, right? Are you sure? The compiler
hasn't "optimized" you into problems here?

You're working with enterprise websites. You obviously support 2FA; and you're
probably going to want to support SSO with SAML2, and definitely integrate
with Active Directory over LDAP.

And your password reset flow- just send an email with a magic link? do you
generate the magic link's token with a CSPRNG? Is it long enough? When does it
expire? And admins probably have to be able to reset anybody's password, but
with strong auditing and accountability features...

You store user info in the session information- basically caching it out of
the database? How do you invalidate sessions after a user changes their
password or has their account disabled?

Can somebody put Unicode in their password?

You're writing a POST handler. You protect against CSRF, right? (yes, tricking
somebody into logging in as another user can be very useful!)

Doesn't seem so simple to me...

~~~
sammorrowdrums
I think most people don't realise how many attack surfaces there are.

Good TLS and salt + strong hash solve the simple cases of DB theft and network
MITM... But that's the bare minimum amount of protection.

As it does nothing for tokens being stolen, sessions, password reset hacks and
emails being compromised.

It does nothing for stopping users trying to brute force. Password strength,
loads of things mentioned.

I think the point is not really needing to know what good libraries mitigate
against, but that you probably (as an individual) don't know all the ways that
things can be compromised, and can't easily remember to implement them all, so
you want a system that has been created, tested and improved by many security
conscious people and out in the wild.

You probably wouldn't build your own lock for your front door either. The
risks simply outweigh the benefits.

~~~
ta999999171
The most common front door locks sold are the ones people who pick can open
the fastest, perhaps a bad analogy?

~~~
sammorrowdrums
I can see what you mean, but that's not to say a normal person would be likely
to do it better themselves though. Lock levels are selected (perhaps naïvely
sometimes), based on a certain tolerable level of inconvenience and cost
factor.

Luckily software is cheaper to implement strongly, but still email + password
is usually selected as the method in spite of being the easiest thing to crack
(as far as getting into individual accounts is concerned).

We could get users to all use ubikeys or more complex forms of multiple factor
auth.

We could make it so that if you compromise an email account, you can't just
reset all the external account passwords using it.

Plenty of sites allow insecure passwords that are in rainbow tables and cannot
defend against targeted attacks (unless a user actually selects a strong
password themselves).

Also just as houses often have big windows that can be smashed, perfect crypto
/ secure auth practices fail to work with the presence of an exploit somewhere
else in the stack are frequent sources of compromise too.

It's not a perfect analogy of course, but actually I don't think locks /
houses is a bad one. Users don't value security enough to want the most secure
locks on their accounts and frequently get annoyed if asked to use 2-factor
Auth, multiple passwords for single sites etc.

------
cs02rm0
Last time AWS Cognito, and at least initially, Amplify.

I'd never write it from scratch. It's always a PITA, there's always
significant compromises - do you make people sign up, do you let them use
Google/every other available federated login provider, what 2FA options, will
it work on a locked down network, etc.

~~~
friedman23
I want to use cognito but the documentation is not good. For example, how do I
use cognito to authorize against an api I wrote? It's not clear from the
documentation.

~~~
stephenemslie
You'd probably use a custom workflow backed by lambda functions that interact
with your api:
[https://docs.aws.amazon.com/cognito/latest/developerguide/co...](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-
user-identity-pools-working-with-aws-lambda-triggers.html)

------
javajosh
Warning: this post is about a speculative design unproven in production.
Definitely use the de facto standard framework in any production code you
write!

I get so depressed with authentication complexity. Seems to me there are two
ways to avoid it: first, write a service that doesn't care about user identity
(it is a fun exercise to think of such a thing!), and second, secure
_messages_ , not connections or sessions.

Securing messages with public/private key encryption, I believe, is the best
possible general approach. _Thinking in messages_ yields the programmer great
benefits, not just inside code (it is the cornerstone of the OOP paradigm,
after all), but outside of code (message passing is also the cornerstone of
distributed programming). Even if you are building a webapp it helps to think
in terms of something more general. HTTP becomes just another channel over
which messages move. Your app can (and probably will) become sensitive to
other channels: email, SMS, webhooks, etc. If you embrace message-level
security then you can _ignore the channel and deal with the message_. Channels
may change, but your application code doesn't need to.

For an SPA, the key problem (no pun intended) is that a users private key is
on the users browser, in the simplest implementation, accessible by everything
on the page. If you're not end-to-end encrypted and don't use 3rd party
resources at all (its possible!) then the naive solution is fine. The most
robust solution is to use a browser extension to isolate the private key. The
site requests encryption services from the extension.

Another fun and interesting problem is the multi-device user. Do we allow
copying the private key, and if not, how do we associate private keys
together? I think this is a fun problem from lots of angles, particularly the
prospect of your own devices inviting each other to share an identity.

~~~
scottmotte
Novel and I like the mental model. It seems like this pushes more of the
management to the user - to manage the key. Or providing the user nice
consumer tools to manage the key - adjacent to your core product. The hard
part here is probably getting consumers to use/download/install that tool.

~~~
javajosh
_> The hard part here is probably getting consumers to use/download/install
that tool._

I agree. I think there are ways to mitigate this, though. If the extension is
open source, and very small then at least the digerati would be more open to
it, and then it might become a standard extension, like ublock origin.

------
fantyoon
I use bcrypt to hash the user password and then store it in a database. When
the user wants to log in I use the compare function of the bcrypt library. If
the hashes match I set a session cookie.

I suppose if I worked on projects that wanted to support OAuth I would use
Passport.js, but I don't know how much I would trust the any but the largest
packages for that.

------
domlebo70
I use Auth0. Works well enough

~~~
folkhack
Auth0 for complex stuff is pretty outstanding in my experience! It's nice to
get sane and reliable OAUTH as a service...

I've rolled a lot of different custom authentication solutions for small apps
with a handful of users all the way up to millions of users and thousands of
concurrent sessions... having an "out-of-box" service saves a TON of time and
headache =)

Not affiliated with Auth0, just love it to all heck. The free-tier offering is
very fully-featured - try it out!

------
chauffer
I use [https://www.pomerium.io/](https://www.pomerium.io/) for my internal
services with Google oauth. I like it because unlike oauth-proxy I can define
which users are allowed to which (sub)domains. I run this in Kubernetes and it
supports forward authentication, so adding a new service is editing a
configmap to let pomerium know about the domain and its allowed users (support
for defining this in the ingress is coming), and adding a few ingress
annotations.

------
skyfantom
In some Rails projects i use Device gem, or simpler version made by my own
(salted passwords in database, and user_id as jwt in session store).

~~~
ksec
For Ruby, There is also Rodauth [1]

[1]
[http://rodauth.jeremyevans.net/why.html](http://rodauth.jeremyevans.net/why.html)

~~~
skyfantom
Thanks for the link, Rodoauth looks interesting. Especially that all JWT
things is already included.

------
kcolford
I use keycloak. It's just like auth0 except it's self hosted and I run it
alongside all my other instances.

------
zwarag
I'm not currently solving it that way but my next side project definitely is
going to try out metamask as the mean of authenticating the user.

A friend of mine showed me some "dapps"(decentralized apps) that he uses
(uniswap.io, axieinfinity.com and some other i forgot). They all used metamask
as the "login platform". The point is that you have your key in this metamask
plugin that is stored in your browser and you can sign things. That means you
get a challenge from the server and metamask then asks you if you want to sign
that challenge. The hole onboarding experience was super easy and you
theoretically could use that to pay for some premium features of a service.

I thought that is really cool because you don't need to enter email, username,
password and whatnot. You just click authorize and you're in.

~~~
gremlinsinc
It works if your app is only used by crypto crowd.. I'd never use it though, I
don't want to have to have metamask installed in my browser.

------
clintonb
I use Django’s included authentication.

~~~
anticodon
For Django projects I prefer to start with django-allauth. Saves lots of time
later.

~~~
scaryclam
Can you elaborate on why? I've used Django a lot and have yet to find auth a
problem after running things for quite a while, so I'm curious what the issues
might be that django-allauth helps with.

~~~
clintonb
Django-allauth provides templates, the ability to login with email, and other
functionality that drastically improves the UX over what is included with
Django auth. Django auth is still used on the backend.

------
pharaohgeek
Simple: Don't. Developing a secure authentication service is actually more
difficult than it would seem on the surface. I've come to rely on an external
authentication service (or, if necessary, a reputable library/framework
specifically designed for it). These days my go-to is Keycloak
([https://keycloak.org](https://keycloak.org)). It supports pretty much
everything: standard username/password, MFA, SAML, OIDC, etc. Plus, it's
easily deployable within a Docker container so standing it up is a breeze.

~~~
sarakayakomzin
I'm certainly going to trust an authentication service with a bad certificate.

~~~
alireza94
Well, the URL is missing www so you see the bad certificate error; Although, I
agree that they should have handled automatic redirection from non-www to www.

------
etherio
I have been implementing different methods for oauth: \- building my own
handling with hashed passwords stored in the database \- using the fantastic
sorcery [0] gem for Rails. It's a light-weight auth solution that allows me to
customize many different aspects of auth while providing a solid structure. It
also has many sub modules that can be added for oauth, resetting password or
stronger application security.

[0] [https://github.com/sorcery/sorcery/](https://github.com/sorcery/sorcery/)

------
anonymoushn
My users send their password over TLS. I check the password using bcrypt. I
assume further communication over the same connection comes from the user.

~~~
pushpop
Do you use a salt?

Also how do you determine what is the same connection and what mechanisms do
you have in place to prevent someone stealing that session?

~~~
anonymoushn
bcrypt does not allow me to not use a salt. A connection is the same if it's
the same file descriptor and it's been open continually. My client uses public
key pinning to ensure it is talking to my actual server. I don't have any
mechanism to prevent someone who can break TLS and take over TCP connections
from impersonating users in my online game.

~~~
pushpop
Re salt, presumably you’re storing that bcrypt as a hashed string though?

Re TCP connections, I was thinking HTTP proxies. Sounds like this isn’t HTTP
traffic though so that’s not an issue.

Also why was my previous comment negative karma’ed? All I was doing was asking
a couple of questions on a post that’s quite vague. The amount of abuse HNs
rep system gets is pretty absurd.

~~~
muldvarp
You're getting negative karma'ed because your comment shows a lack of
understanding of what bcrypt is and what it does. Here's a short explanation:
bcrypt is a hash function that you should use for storing hashed passwords.
When calculating the bcrypt hash of a string, a salt is automatically added.
The result you get looks something like this:
`$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy` The 2a
specifies which version of bcrypt was used, the 10 is the number of rounds,
N9qo8uLOickgx2ZMRZoMye is the salt and the remaining characters are the hash.
When checking this hash against a password you have to call a second function
and pass in the password as well as the hash. This second function will
automatically parse the passed in hash and calculate the hash of the password
with the same number of rounds and the same salt.

~~~
pushpop
Nar, I’m familiar with bcrypt. I was just getting bcrypt mixed up with scrypt.
Doh.

Even so, that’s still not a good enough reason to -rep without feedback.

------
tooop
Laravel built in auth, Socialite for social logins.

------
forgotmypw
I am working on a hyper-open, hyper-compatible, and hyper-accessible forum
system with accessibility by historic browser included in the spec.

I use a multi-layer authentication system with various levels of
compatibility, security, and accessibility.

* The default mode is unauthenticated, which allows the user to post plaintext. Optionally, this can be backed by a device fingerprint, which would group all of this user's posts together. This is supported by all post-Mosaic browsers, except perhaps Mosaic 1.0, which does not support HTML forms. (For Mosaic, there is a fallback writing mode, of the form [http://example.com/your+message+here](http://example.com/your+message+here))

* There is also a cookie-based authentication system, in which the user asks for a new ID, and the server sets cookies for user id and checksum. The checksum is checked against a server secret via hashing, so no storage of account data is needed on the server. This works with all cookie-supporting browsers.

* The other authentication system is based on PGP, and allows the user to either use in-browser PGP (insecure) or client-based PGP (less insecure) to sign their messages. These messages can be both client verified and grouped together into a profile on the server.

------
polishdude20
If I use a an external framework or library to let me users login via Google
or say outlook, do I need to have my own outlook or Google account? Do I need
some authorization to do this if say my company uses outlook for their emails
and I want to let my co-workers use their account info to sign in through
outlook?

~~~
jchw
Typically to integrate OAuth2 based authentication flows, you need an OAuth
Client ID and Client Secret that identifies and authenticates your application
with the provider. Generally this requires an account of some kind, though it
may not always be identical to a normal user account on all systems. For
Google you would need a Google account, its managed in Cloud console (though
any kind of account will work.)

I actually don’t know if you need this if you just want to identify the used,
off hand; I know there is a separate flow for that when using OIDC, but I
suspect it still would have at least a Client ID. (This would be used for the
provider to display your application name and possibly some other info.)

------
brylie
Django user authentication:

[https://docs.djangoproject.com/en/3.0/topics/auth/](https://docs.djangoproject.com/en/3.0/topics/auth/)

------
DerekQ
Does anyone know if there's a decent, comprehensive library that handles all
authentication / login for .Net Core apps? Bonus points if there's a SSO
addition (even if that part is commercial).

~~~
jddj
Identity.NET for embedding a library, Identity Server for hosting a service.

They're not the simplest, and unfortunately the scaffolding story with
Identity.NET is a bit of a nightmare for MVC apps (if you're not careful, you
can end up with a ton of hidden-but-accessible razor page endpoints), but the
code is robust and most cases are covered.

Identity.NET will also need you to write your own implementations of a couple
of database access classes if you don't want to drag a dependency on Entity
Framework Core along for the ride.

Documentation is fairly dry and mostly complete (Microsoft style) but be
careful with versioning because dotnet core moves fast.

~~~
DerekQ
Fantastic. Thanks very much for that.

------
antoineMoPa
Rails + devise even if my application is in another language than Ruby.
Laravel could also do the job. Every time I have looked, authentication tools
in Javascript are paid or overengineered.

------
alanfranz
Keycloak. Open source IDP.

------
Pandabob
I've been eyeing Firebase authentication for a Django project of mine, but
haven't implemented it yet. Can anyone recommend it or advise against it?

~~~
kayoone
I've used Firebase for authentication and it works pretty well and has good
documentation. I haven't tried other options such as AWS Amplify though. I
just keep a user reference in Firebase and then do everything else in my own
app/db.

------
mmusc
In .net world aspnet identity give you a basic login, can add social logins
and identity server adds auth2 support. Both highly customizable

------
Ken_Adler
For user authentication: Hosted (Auth0 or Okta), self-hosted: Hydra

For Service Identity: SPIRE/SPIFFE... (or Oauth CC flow if mTLS is not
possible)

------
sendilkumarn
keycloak is really awesome. This also makes sure when you move to any other
oAuth2 authentication, we can simply switch the server details.

On the other hand firebase authentication is very scalable easy to set up and
start.

Dont write it from scratch, if you are in JVM, Spring Security provides a
robust implementation, we can just plug, configure and play

------
vbsteven
Spring Security for the logic and password storage. I usually build my own
pages for password resets and logins

------
mister_hn
In my services, I use a combination of:

\- hashed password or webauthn token \- palm vein or usb token or (less
preferred, SMS)

------
treve
we've been plugging away at writing an open-source OAuth2 server:
[https://github.com/curveball/a12n-server](https://github.com/curveball/a12n-server)

------
kitsune_
Keycloak

------
rp2684
One very important aspect of authentication is session management. Doing this
wrong (or naively), can have catastrophic effects for your app!!

Let me provide an example: It's common knowledge that JWTs are very common. A
lot of people who use JWTs, implement them as access tokens for their APIs.
JWTs also require a shared secret key - what if this is stolen? Then an
attacker can use that to hijack any user's account very trivially, and you may
not even realise that it's happened! This is far worse than anyone getting
hold of hashed passwords from your database.

That being said, I use the following flow for session management: \- User logs
in, the backend issues a short-lived (~1 hour) JWT and a long-lived refresh
token and sends them to the frontend. \- The frontend sends the JWT for each
API call while it's still valid \- In the event that the JWT has expired, the
frontend should then use the refresh token to get a new JWT AND a new refresh
token (rotating refresh token - see
[https://tools.ietf.org/html/rfc6749#section-10.4](https://tools.ietf.org/html/rfc6749#section-10.4))
\- If the refresh token expires, then the user has to login again.

While this sounds quite straightforward, the key here is to use rotating
refresh tokens - that's what actually makes it fare more secure than just
using simple refresh tokens (i'd argue that it's almost the same level of
security as just using a long lived access token)

Some of the benefits of this approach: \- You can detect token theft! If an
attacker gets hold of the refresh / access token, because they keep changing,
you can detect if an old token is used which is a strong singal of theft (see
the RFC link above) \- You can change the JWT secret key without logging any
users out: Once you change the key, all JWTs are instantly invalidated. But
then your frontend client can simply use its refresh token to get a new access
token signed with the new signing key (along with a new refresh token). \-
Allow your users to be logged in for however long you want without
compromising security.

Some implementation gotchas: \- When changing the refresh token, be sure to
not invalidate the older token unless your backend is sure that the frontend
has received the new token. This can be confirmed by the frontend using the
new access / refresh token. This is important since if not done, and if the
user is in a bad networked area, it can lead to them being logged out. \- See
this blog and specifically this race condition:
[https://medium.com/hackernoon/the-best-way-to-securely-
manag...](https://medium.com/hackernoon/the-best-way-to-securely-manage-user-
sessions-91f27eeef460#e81c)

If you do not want to implement this on your own, you can also check out
[https://supertokens.io](https://supertokens.io) \- It provides an end-to-end
implementation of the above taking care of all race conditions and network
failure issues. It also prevents other common web attacks which are on the
OWASP top 10 list.

\-----------------------

In terms of user authentication for the login part, I prefer using a no-
password method - email or SMS OTP. The reason for this is that I do not have
to care about managing user passwords (though that's not too difficult), I do
not have to build forgot password flows, and most importantly, users don't
have to remember yet another password.

I also only allow 3 attempts for OTPs per OTP. So after sending the OTP, if a
user fails to input the correct one 3 times, then I revoke the old OTP and
send a new one (this is so that someone can't simply brute force their way
into an account). If the user login is successful, then I revoke all OTPs for
that user. If the user clicks on sending the OTP again, then I send a
different OTP (but the old one is still valid). This allows me to have a an
OTP timeout of say 1 hour - which is more than enough!

According to me, this coupled with the above session management flow, is
perfect!

------
pushpop
Another thing to bare in mind, for those who are rolling their own, is how you
caress those passwords from the DB.

The common approach is a simple DB SQL select. But that then means if your web
server gets exploited an attacker can dump the entire password database.

The safer option is to write a stored procedures to return or modify that
table and set permissions on that table so even your web app creds can’t
directly query the password table. Then your web service only has access to
check a single password, rather than downloading every hash on the DB.

If you can also offload the encryption/decryption and hashing then that is
another step forward too.

~~~
pushpop
Anyone care to elaborate how this post is wrong?

Hint: it isn’t. But I’ve been penalised for it all the same

~~~
colinclerk
I'll bite. It doesn't seem obviously wrong to me. I would also love to know if
I'm misunderstanding something.

I've never seen it done this way, but I think postgres pgcrypto could support
this.

If I had to guess, I haven't seen it done this way because authentication
frameworks are not normally in a position to lock down access to the database
in this way (e.g. it couldn't create a password table that the web app
credentials can't see, because it's integrated into the web app and uses the
web app credentials to create the password table). The way they typically
behave is: \- When updating password, run bcrypt in the web server and INSERT
\- When testing password, SELECT the bcrypt hash down to the web server, and
test on the web server.

Have you used this stored procedure strategy in production? I'm particularly
interested if it's caused any challenges with resource usage in the database
server?

The top answer in this stack overflow question makes the argument that you
should bcrypt in the web server to lessen the time it's unhashed: > Use php
bcrypt if you can, it'll lessen the time that the password remains unhashed.
[https://stackoverflow.com/questions/2647158/how-can-i-
hash-p...](https://stackoverflow.com/questions/2647158/how-can-i-hash-
passwords-in-postgresql/18687445)

I'm not sure I agree with this argument, unless perhaps the database is hosted
by a separate vendor (which would mean another party is receiving the unhashed
password). Also note: the strategy proposed in that answer doesn't have the
benefit of a stored procedure preventing a SELECT all, so maybe the less time
argument makes sense in that case.

Perhaps there's a valid discussion around - is this going overboard? Is
preparing for a leak of web app database credentials an attack vector we
really need to prepare for? If we do, are password hashes the critical data we
need to be securing in this manner? When hashes leak I've been asked to change
my password as precautionary measure, but hashing algos are such that this
event shouldn't be catastrophic. Unlike a credit card number leak, for
example, which would cause a bigger headache.

~~~
pushpop
I learned this technique when I worked on the blue team of a cyber security
firm.

It’s not about sending your passwords in clear text to your RDBMS. You’d still
use bcrypt like you normally would but instead of querying the password table
directly you’d have that prewritten as a stored procedure. That way you can
have different permissions for the password table.

Some frameworks and/or other managed solutions might already be doing this but
it’s worth mentioning anyway since people are talking about hand rolling their
own auth.

I don’t know why I added the part about offloading encryption though. That
doesn’t make sense. I guess that will teach me talking security before my
first coffee of the day

~~~
colinclerk
I can't really use bcrypt like I normally would, since bcrypt normally*
concatenates the cost and salt into a single string with the hash that I store
in my database:
[https://en.wikipedia.org/wiki/Bcrypt](https://en.wikipedia.org/wiki/Bcrypt)

I believe I can split out the cost and salt. That would let me:

1\. SELECT the user's salt and cost from a table that is accessible with my
web app credentials.

2\. Run bcrypt on the user-provided password with the selected salt and cost
within my webapp.

3\. Ask my stored procedure if my resulting hash matches the hash in the
database, even though I cannot SELECT the hash directly with my web app
credentials.

Am I understanding this correctly? I imagine it would have been easier pre-
bcrypt, when generating salts was less abstracted away from the developer.

I can't think of a reason this wouldn't work, and it adds a layer of security
if implemented properly. But I say that hesitantly, as I would all things
crypto, particularly since I wouldn't consider it common practice and I'm not
sure if I'm overlooking something. I'm pretty sure I'd need to hack on bcrypt-
ruby more than comfortable to actually implement.

* I say normally because that's what the wiki says and how bcrypt-ruby behaves, but I haven't done wider research.

