DEV Community

Passwordless Authentication with Cognito

Duarte Nunes on May 22, 2020

Passwordless authentication is a broad term for any authentication method that doesn't rely on passwords. Implementations typically perform proof o...
Collapse
 
oldtinroof profile image
Les Cochrane

Thank you Duarte, this has been a fantastic post for me to get my head around OTP with Cognito - I'm porting it over to JS as I've got more experience with that but I'm stuck on the last couple of steps.

Is the auth you call for auth.SetAttributes, and auth.CreateUser from an SDK, or a private library?

Collapse
 
duarten profile image
Duarte Nunes

Glad you enjoyed it :D

The auth module is a private library. Essentially, SetAttributes() wraps AdminUpdateUserAttributes, and CreateUser wraps AdminCreateUser and AdminSetUserPassword with a random password.

Collapse
 
oldtinroof profile image
Les Cochrane • Edited

Awesome, that's exactly the nudge in the right direction I needed, thank you.

One of the things that sets your post apart (in a positive way) is that you didn't give code for every single step, so it's encouraged me to go research and really understand what's going on and write my own equivalent of the auth library. Cheers!

Collapse
 
shirikodama profile image
Michael Thomas

so is this a truly passwordless system? that is, a password is never sent over the net at any point ever to an auth/enroll server? i've been working on an example of exactly that kind of system where it uses asymmetric keys to enroll and authenticate users. i'm aware of webauthn but it is heavily focused on crypto dongles which is vast overkill for most situations (say this site, for example). using WebCrypto to generate key pairs and signing login requests allows the server to just need to remember the public keys associated with a given user and an out of band (email, sms...) way to verify their possession of that method.

it's all pretty simple honestly, and it's something of a mystery why it's not gaining traction since webcrypto has been a round for a while now.

you can check out my example and code here: out.mtcc.com/hoba-bis

Collapse
 
duarten profile image
Duarte Nunes

Interesting approach :) However, that does require some effort from users as they have to store their private key on their devices. In our system, users are authenticated through social login or through an OTP as described in the post.

Collapse
 
shirikodama profile image
Michael Thomas • Edited

js code makes it completely transparent to the user. in my example, you join by typing in a username and an email address then click join. you login by entering your username and clicking login. all of the complexity is under the hood, with the keys (wrapped by a local password if you want), stored in localStorage or indexedDB. it's not even particularly complex and pretty much resembles existing login code. the backend just verifies the key bound to the user and verifies the sig. i patterned the exchange after digest auth (rfc 7616). i came up with this years ago and documented it in rfc 7486 well before webcrypto and webauthn.

Collapse
 
jrothman profile image
Joel Rothman

Hi Duarte - thanks for the post. I'm a bit of a Go and Cognito noob, so apologies if this is a dumb question. When I try setup my lambda functions there are a number of dependencies that they need that I cannot figure out, for example: auth.Challenge and request.Session. Could you provide some assistance in terms of the packages (and anything else you think I should know) in order to configure and run your example?

Collapse
 
duarten profile image
Duarte Nunes

Hi Joel, apologies for not preparing a runnable example. auth.Challenge is my own type, defined as

type AttributeType string

const (
    Email       AttributeType = "email"
    Phone       AttributeType = "phone_number"
    NoAttribute string        = ""
)

type Challenge struct {
    Attr AttributeType
    Code string
}

request.Session is a member of CognitoEventUserPoolsCreateAuthChallengeRequest, the type of the Request field in CognitoEventUserPoolsCreateAuthChallenge. The latter is the input type of the Lambda function for the create auth challenge trigger.

Hope that helps.

Collapse
 
jrothman profile image
Joel Rothman

Thanks Duarte - much appreciated!

Collapse
 
geekmidas profile image
Lebogang Mabala

Hey Duarte, I've been trying to follow what you are doing here and I understand for the most part, but you seem to be using a lot of code that is not show here. Do you mind sharing the public repo for this solution? On the other hand it also seems like you are handling both login and sign up in your lambda above. How would you keep the user logged in on the frontend when the tokens expire,. maybe I am not following some of your logic. Thanks in advance.

Collapse
 
hadilsabbagh profile image
Hadil Sabbagh

Hi Duarte! Thanks for the excellent post. I am porting it to Clojure. I have a question:

In the deliverCode function, how do obtain the email address or phone number associated with the user?

Collapse
 
dhananjayrakshe profile image
Dhananjay Rakshe

can I get full source code for this