title: What's the correct usage of Friend's bcrypt-credential-fn?
body: <p>I'm building a simple practice web-app, working on login with friend, and am trying to transition from the tutorial examples dummy in-memory database to accessing my DynamoDB database.</p>
  
  <pre><code>(handler/site
  (friend/authenticate app{
                       :login-uri "/login"
                       :unauthorized-redirect-uri "/login"
                       :credential-fn (partial creds/bcrypt-credential-fn users)
                       :workflows [(workflows/interactive-form)]})))
  
  (defn users
  [uname]
  (read-string (get-in (db/valid-user? uname "UB") [:item :friend-map])))
  </code></pre>
  
  <p>The problem arises with my users function, my understanding(and this could very likely be where I'm wrong) reading the friend source-code is that bcrypt-credentials-fn calls the next function with an argument of the username provided from the /login. Examples/tutorials I've seen around seem follow that pattern.</p>
  
  <p>If I call users with a username like, "bob@bob.bob", it returns a hash-map with friend credentials</p>
  
  <pre><code>{"bob@bob.bob" {:username "bob@bob.bob", 
                :password "$2a$10$rtDxqCqZRIRFFzjCYD9d.uiQ2NuUMXto.jCbWNPtVKF1y/d4WPL/C",          
                :roles #{:practice.models.db/admin}}}
  </code></pre>
  
  <p>If I hard-code a username into the users function, it works fine and I can log in with it, but when replacing it with uname, or (str uname), just to make sure it's a string. I get a null-pointer exception</p>
  
  <pre><code>java.lang.NullPointerException
  BCrypt.java:663 org.mindrot.jbcrypt.BCrypt.hashpw
  BCrypt.java:763 org.mindrot.jbcrypt.BCrypt.checkpw
  credentials.clj:18  cemerick.friend.credentials/bcrypt-verify
  credentials.clj:47  cemerick.friend.credentials/bcrypt-credential-fn
  AFn.java:163    clojure.lang.AFn.applyToHelper
  AFn.java:151    clojure.lang.AFn.applyTo
  core.clj:619    clojure.core/apply
  core.clj:2396   clojure.core/partial[fn]
  RestFn.java:408 clojure.lang.RestFn.invoke
  workflows.clj:80    cemerick.friend.workflows/interactive-form[fn]
  friend.clj:180  cemerick.friend/authenticate*[fn]
  core.clj:2485   clojure.core/map[fn]
  LazySeq.java:42 clojure.lang.LazySeq.sval
  LazySeq.java:60 clojure.lang.LazySeq.seq
  RT.java:484 clojure.lang.RT.seq
  core.clj:133    clojure.core/seq
  core.clj:2523   clojure.core/filter[fn]
  LazySeq.java:42 clojure.lang.LazySeq.sval
  LazySeq.java:60 clojure.lang.LazySeq.seq
  LazySeq.java:82 clojure.lang.LazySeq.first
  RT.java:577 clojure.lang.RT.first
  core.clj:55 clojure.core/first
  friend.clj:180  cemerick.friend/authenticate*
  friend.clj:208  cemerick.friend/authenticate[fn]
  keyword_params.clj:32   ring.middleware.keyword-params/wrap-keyword-params[fn]
  nested_params.clj:70    ring.middleware.nested-params/wrap-nested-params[fn]
  params.clj:58   ring.middleware.params/wrap-params[fn]
  multipart_params.clj:106    ring.middleware.multipart-params/wrap-multipart-params[fn]
  flash.clj:31    ring.middleware.flash/wrap-flash[fn]
  session.clj:85  ring.middleware.session/wrap-session[fn]
  resource.clj:24 ring.middleware.resource/wrap-resource[fn]
  file_info.clj:63    ring.middleware.file-info/wrap-file-info[fn]
  middleware.clj:12   hiccup.middleware/wrap-base-url[fn]
  Var.java:415    clojure.lang.Var.invoke
  reload.clj:18   ring.middleware.reload/wrap-reload[fn]
  stacktrace.clj:15   ring.middleware.stacktrace/wrap-stacktrace-log[fn]
  stacktrace.clj:79   ring.middleware.stacktrace/wrap-stacktrace-web[fn]
  jetty.clj:18    ring.adapter.jetty/proxy-handler[fn]
  (Unknown Source)                                         
  ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$0.handle
  HandlerWrapper.java:111 org.eclipse.jetty.server.handler.HandlerWrapper.handle
  Server.java:349 org.eclipse.jetty.server.Server.handle
  AbstractHttpConnection.java:452 org.eclipse.jetty.server.AbstractHttpConnection.handleRequest
  AbstractHttpConnection.java:894 org.eclipse.jetty.server.AbstractHttpConnection.content
  AbstractHttpConnection.java:948    
  org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content
  HttpParser.java:857 org.eclipse.jetty.http.HttpParser.parseNext
  HttpParser.java:235 org.eclipse.jetty.http.HttpParser.parseAvailable
  AsyncHttpConnection.java:76 org.eclipse.jetty.server.AsyncHttpConnection.handle
  SelectChannelEndPoint.java:609  org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle
  SelectChannelEndPoint.java:45   org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run
  QueuedThreadPool.java:599   org.eclipse.jetty.util.thread.QueuedThreadPool.runJob
  QueuedThreadPool.java:534   org.eclipse.jetty.util.thread.QueuedThreadPool$3.run
  Thread.java:722 java.lang.Thread.run
  </code></pre>
  
  <p>What am I doing wrong here?</p>