Can/should IdentityServer4 be used to create a token for user-email verification - asp.net-core

I have IdentityServer4 setup for API authentication although I have a use case where I want to verify that a guest (user) is essentially a valid user. A valid user in my case is anyone with a valid email address, so I want to do the following:
send the user an email with a verification token (preferably something which is a mash up of their email address, some salt and an expiry
the user can then enter this token into my app and they are "allowed" to go ahead
I was wondering if IdentityServer4 can/should be used to achieve the above?
Their tools show that you can generate a token although I am very new to this topic so was hoping for some guidance.

No, the tokens Identity Server deals with are access_tokens which are to do with claims-based authentication.
The tokens you need to use for email verification are commonly referred to as User Tokens, or one-time passwords (OTP). You can find a wealth of information on how to generate/consume these using those search terms but if you use the aspnet identity classes such as the UserManager you will find it has some in-built read to use. Or you can register your own UserTokenProvider with the UserManager.
In general you'd do something like this:
Use your UserTokenProvider to get a token (otp) for a specific user. The UserManager will use the security hash of that user and your own 'reason' (e.g. "EmailVerification") to generate the short OTP.
You could then wrap that OTP into an object that includes the email address, a userid maybe, and whatever you like. Safe Base64 encode it (there is a helper function within Identity Server that has this in fact, making sure it doesn't have the superfluous _ at the end which will mess with HTML links), put it in an email to the user
User clicks your link which takes them to your 'verify password' controller, with your mashed up token as payload. You decode it, work out which user it was for, get UserManager to verify the OTP part is still valid.
Job done.
If you want them to enter the OTP into your app directly, while logged in, then you could just skip the whole mash-up part of emailing a link, and email the short OTP directly.

Related

Login with phone number feature

Currently I am working on feature login with phone number, user will enter their phone number and server will send sms which contain OTP.
I have researched many days for the solution to integrate with Keycloak but still stuck on it. I saw that we need to use authenticator SPI, extend keycloak and implement code which we want.
I also have thought about using other third party to handle sms and otp stuff ( like Firebase) and then will use firebase token to exchange keycloak token but firebase is not supported provider in Keycloak therefore can't do this flow
I just want to ask is there any other ways to do this feature without extend Keycloak? or simply can we get keycloak token via API but without password
I can imagine small solutions around keycloak, which together can get what you want. Will try to explain :)
Imagine phone number is user login in keycloak.
Imagine password is system generated, like encoded phone number + salt; basically hash algorithm know what the password is, user don't.
You use third party library, which verify user mobile number and text message user enters, and it works.
You create system-user in keycloak, keep password encoded in application.properties, assign him some admin roles like create user, query user, something else you need to manage users.
And now, workflow is:
User enter mobile number 123, sms getting send
User verify sms,
you know user number 123, you generate password
hash1(hash2(123+salt)) (see point 2)
Using system-user you login to keycloak, get accessToken for system-user
using accessToken check if user exist, if not, create user 123 with password hash(..), assign default roles, groups
logout from system-user
login with user 123 and password hash(..), load user accessToken, build User Profile, put in to SecurityContextHolder.getContext()
If you make all small bits working, should work all together.
or just ignore me if I am wrong! Good luck !

Creating a "pre-signed/tokenized" URL which skips the login step (Json Web Tokens)

I'm working on an application where an administrator will send a unique link to a user for them to fill out a form. The system requires authentication in order to fill out a form, however I would like this unique link to "skip" the login step for the user. ie when the user receives the link, they can simply click it and fill out the form without logging in, but behind the scenes the user is actually authenticated with a Json Web token. Ideally I would like the link to never expire, or possibly after 1 year so the user could use the link 6 months down the road and the link will seamlessly still work for the user.
The most obvious solution would be to generate a JWT token with a lengthy expiry when the admin generates the link and just include the token in the url that is sent to the user. When the user receives the link, they already have a JWT token so they don't need to login. However this feels like it may be insecure because now the user has a JWT token for their user with a long expiry sitting in their email inbox.
I think I might be able to include information in the JWT token that would restrict it for that specific purpose (filling out the form), but I'm not even sure if I'm on the right path here.
What is the best way to do this, is there any other recommended ways to create sort of a "pre-signed" url that skips the login step?
I'm using ASP.NET Core as the backend, but I'm not sure if it's relevant as this is more of a general authentication / JWT problem.
doesn't matter what precautions you take, anyone who gets a hold of the email would be authenticated. I would consider PGP (or the like) in sending email to user.

"Forgot username" flow for AWS Cognito?

I'm using ASW Cognito for authenticating users. Cognito has a well-documented flow to handle users who have forgotten their passwords.
How do I handle users who have forgotten their usernames? Is there a built-in flow that lets the user enter their email or phone number, and then receive an email or text with their associated username? I found the ListUser API, which returns all the users in a userpool. I could write a Lambda function that filters through all my users, looking for a match on email or phone number. But this seems like overkill.
Unfortunately, there is no default out of the box workflow of "Forgot Username".
I am implementing similar workflow. We ask user for their registered phone number/email, and we retrieve username based on that number and send it to email/phone according to configuration. If user is configured to use email and phone both, we send SMS to phone if user forget username (which is email id they used during sign up).
One major drawback of this approach is that, we need to provide ListUsers API call access to anonymous user which is a potential security issue but can't seem to find any other way by which we inform user about their login details.
For those, who are looking for the solution, don't give the anonymous user access to ListUser API as suggested in the accepted answer.
There are two ways to implement 'Forgot username flow'.
Enable email as an alias for your Cognito User Pool:
Calling this API causes a message to be sent to the end user with a
confirmation code that is required to change the user's password. For
the Username parameter, you can use the username or user alias. The
method used to send the confirmation code is sent according to the
specified AccountRecoverySetting.
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html
The user will be able to reset the password with their email and code delivered to provided email address. If you still want to remind the username, you can use Lambda trigger to generate the password reset email with both username and verification code.
Use the backend (web server or lambda) which will receive the email address as an input to the 'Forgot username flow'. The backend will have permissions to invoke List Users API (https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListUsers.html) and will perform user lookup using the email. You now can go into Forgot Password flow using the retrieved username. Lambda trigger will be used to generate password reset email with username and verification code.
You can protect this API from abuse using WAF and/or captcha.

Can I Firebase createUser with an arbitrary ID instead of an email address

I'm using Firebase for an Atlassian Connect AddOn. I want to use Firebase users to secure the data.
The users will be identified by a clientKey provided by Atlassian (probably after I fudge it a bit) - NOT BY EMAIL.
Ideally, I don't want to have to do my own authentication here, as the Firebase.createUser method would suffice entirely if I could provide something other than an email to it, but I can't find anything like that in the documentation.
Is there a way I can create Firebase users WITHOUT AN EMAIL (just an ID and password), without going to all the way into oAuth and all that jargon to create my own custom authentication?
A Firebase user must have an email. If that is a problem then we can't use a Firebase "user", but instead a "token" (which must have a UID as part of it's payload and hence behaves the same way in terms of security once it reaches their datastore).
If you don't need a password, then "instead of double-authenticating and duct taping" as #Kato kindly pointed out, you can generate your own Firebase tokens and serve them to the client.
If you require the user to provide a password then you'd have to implement your own verification before you generate the token and serve it to the client. Since there's no Firebase user involved anymore, but rather a token your privileged server can arbitrarily create and serve, it's your responsibility to ensure you're doing that at the right time (i.e. when a user has provided your server with an adequate ID and password).
Read more about Custom Authentication here and tokens.

How to implement Querystring authentication

I’m developing a website of a client and they are sending out newsletters to their customers (through the website administration interface)
The newsletters are personal to each of the subscribed recipients/customers.
Each recipient/ customer is also a user with a username/password that enables them to sign in on the website and manage their newsletter subscriptions and participate in the sites community.
This all works like a charm.
Now my client want a “Manage my subscriptions” link in the newsletter email that when pressed automatically signs the recipient/customer in on the website with no need to remember username and password.
This could be easily solved be making a link like this:
http://mysite.com/manage.aspx?user=peter&password=hounddog
Of course information should not be clear text but encrypted in some way.
This however poses a problem since the only way a user can be authenticated on the website if by providing a valid username and password.
In the name of security, passwords are stored as hashed values in the database making it impossible for me to insert the password in the link.
What is the best way to accomplish this without compromising the security?
You will have to compromise your security somewhat, if you want people to be able to login without entering password. Note that even if you had access to the password (as in your example), you would have to embed it in a mail massage which would be transmitted in plaintext.
You can create a Guid associated with each user and message, and append it to the URL, and allow that to login automatically.
You could perhaps isolate the permissions so that a login through a newsletter guid link only allows the user to manage subscriptions, but that a real password-login is still required to participate in the forum. In that case its pretty limited what havoc can be wrecked if someone gets access to a Guid from a mail message.
Could you not insert an encrypted user name bundled with the hash value of the password?
What I mean is, encrypt & encode the user name to always be a particular length or to have a known break character in it then append the passwords hash value. this way, you could break apart the query string easily while still having the user name and password securely encoded. A straight compare of the hash values would be enough, with the unencrypted, decoded user name to allow access.
What about using an encrypted cookie that contains an access token ?
This cookie would be delivered after a successfull authentication by a separate page.
This kind of token can also be part of the URL query string.
Also you might consider using secured https instead of http.