How can I register a new user with a user-defined unique identifier when leveraging OAuth code flow? - c#

I'm building a sign-up / login flow for a web site. I plan to use Facebook as my identity provider instead of rolling my own.
I have a good feel for the server-side login flow with Facebook:
Call FB login API to get a code
Exchange the code for a user access token
Inspect the user access token
Validate the user access token details
After these steps, I'd like to check if the authenticated user is already registered in my system. If yes, simply return a newly generated bearer token, so the user can make subsequent requests to resource servers to access protected data.
If the user is not registered in the system, however, then I'd like to register them by creating a database entry. Before creating this entry though, I'd like to collect one piece of information from the user. Namely, I'd like for them to tell me their desired 'username'. I will use this unique username as my database primary key.
I'm not 100% sure on how to securely ask the user for their desired username before creating the database entry. This is my question. :)
One thought I had was to create a "redemption code". This code would be encrypted and contain the user initialization details, a secret only the server would know, and a timestamp. Something like this:
code: {
mySecret: "super-secret-value",
expirationDate: "date-value",
user: { ... },
}
After seeing the user is not in my system, I'd respond with the code + redirect the client to a page where they'd be able to specify their username. Upon submitting their username + code back up to the server, I could decrypt the code, and validate mySecret to determine the code is not tampered. If all is good, create the user in the database with the user information from the redeemed code. Lastly, I'd generate a new bearer token for the user and send it to the client.
Questions
Is my proposed redemption code strategy a secure way of requesting a username before creating the backend DB entry?
If not, what would be?
If yes, what is a secure encryption/decryption routine to use for this purpose in C#?
Flow Sequence
Steps 1-4 from above correspond to "Login" through "Validate" arrows.
My proposed redemption code strategy corresponds to the purple arrows.
Red text corresponds to Facebook specific nomenclature.
Note, Stack Overflow does something very similar to what I want to do. Before creating your account on SO, it will ask you for your desired Display Name (this happens after authenticating via Facebook, Google, etc.). After submitting your display name, your account is registered.

Use open source IdentityServer3.
Whatever flow you choose its already standardized in their server. Including (if you want or need) OpenID, OAuth2 etc.

Related

How to completely sign out a user using Oauth Prompt?

I have been following the Oauth prompt sample Oauth Sample. Its working great when I login properly and get a token. However I am working on the use case when a user logs in using the wrong credentials. I am using await botAdapter.SignOutUserAsync(innerDc.Context, ConnectionName, null, cancellationToken); to sign the user out and it works since Oauth gets prompted again. However when the user clicks on sign in button again, it takes the wrong credentials again ( i.e same logged in credentials because of browser cache ) and doesn't allow the user to use a different account. I am looking to gracefully sign the user out so that he can choose another account to login. I understand if I add this to the right tenant (add my bot to right AD identity) it wont allow the wrong email/credentials to even get through but its something I have to work through for now. I don't know if this is intended but the sign out only destroys the token doesn't log you out of Microsoft online.
Thanks
Given that the SignOutUserAsync method only signs a user out of the token server, my guess is you will need to implement a custom method to handle a full sign out. This doc discusses sending a sign-out request and should serve as guidance on how to setup. If this isn't a perfect match, other options are listed in the menu tree.
Instead of relying on the SignOutUserAsync method, you would implement this feature in its place.

How to Properly Secure Forgot Password Endpoint

I am designing some Forgot Password functionality in an ASP.NET application, and had a question about the best way to secure the endpoint where a user can reset their password.
How I imagine this to work is (roughly) the following:
User clicks 'Forgot Password' on the login form
User is taken to a screen where they will enter their email associated with their account
User is then taken to a screen where they can answer some security questions (required by my company)
After answering questions correctly, the user will be sent an email containing a link.
User clicks the link in their email which will take them to a password reset form
My question here is, how can I ensure that when someone arrives at this password reset form that they arrived there from clicking on that email link, and didn't just manually type in the URL to get there?
One solution I've thought of was to encrypt some data and append it as a parameter in the URL inside the email. So when they click that link, I can decrypt the data and ensure it came from a valid email before serving the form. But I'm not sure the best way to go about this.
A solution consists of creating a token that can be used once on the reset page. You send by email a link similar to https://example.com/PasswordLost?token=467dc4ad9acf4, then the site checks that the token is valid and displays the password change page. To add more security it is possible to limit the validity of the token in time: about ten minutes are largely sufficient. Once in use, the token should no longer be usable.
There are many ways to generate the token. You can generate a random string and store it in a database with the associated email address and the expiration date of the token. Then, you can validate it by querying the database. The other solution that I prefer, is to generate a token that is ciphered by the server. Then, you can decipher it and validate the data it contains (user email and expiration date, last password changed date). This way you don't have to store anything on the server. This is what ASP.NET Core Identity does.
You can read my blog post about how to implement Password reset feature in a web application? for more information.

ASP.NET Core. How can I invalidate JWT-Token after password change

Sorry for my bad English. I'm writing an application in ASP.NET Core using Vue.JS for client-side. For authenticate user I'm using JWT and ASP.NET Identity. I have a method for change the password. But I can't understand: How to invalide token after password change? I want that the user authenticated in another browser will logout after that. Is there a man who haved a problem like this?
You normally don't invalidate JWT's because they are meant to be short-lived access tokens and therefore after the password change, request for new token will prompt the user to reenter credentials.
If you do absolutely need to invalidate the JWT immediatelly after password change - you need to look into Introspection where your backend api essentially has a backchannel to your token issuer and it can then re-validate token every request. This way if you invalidate token at the issuer side - it will reflect on the api side immediately.
I've been thinking about this and the inability to invalidate a JWT that's already out there may not be built into anything, but is possible.
Here's the narrative: You have an alarm system installed that can be controlled via web and your ex-S/O is logged in to your previously shared account. They are upset and they keep enabling the alarm at random times.
If the web app uses JWTs to store session, you could change your password but the JWT your ex possesses will still be usable for a period of time until the timeout is reached.
Solution 1: short timeout. but what if you want to stay logged in for longer periods (such as a password manager)
Solution 2: logout ALL users by changing the Signing Key of your Certified Authority, basically invalidating ALL JWTs across the board. This is still a less ideal route as I'm sure you can imagine.
Solution 3: track the current JWT for each user in your Users table. If the JWT they possess is different from the current one, then they aren't authenticated. If the user logs out, nullify the stored JWT-data in your Users table which would equally unauthenticate JWTs for that user and force a relogin.
I'd also recommend storing a bool of "logged in" for the user. DO NOT RELY ON THIS. This would be a value to set to true when they log in, set it to false when they log out, and validate the value is 'true' if they ever pass you a JWT. This will ensure that the moment they logout they are forced to reauthenticate.
Assuming you go with solution 3:
When storing JWT data for this solution, I'm leaning towards not storing the entire JWT because it's rather large text to begin with. Alternatively just store the JWS (JWT Signature) which will make the stored value both smaller and unusable if captured for any reason.
Next, it's a hash to begin with so we could just store the last maybe 9 values (9 because int32 max is 2147483647). We just need a bit of uniqueness, not much.
Next, we could avoid the string comparison for validating that the JWS passed is the active one if we use regex to pull the integers out of the JWS and again take maybe the first 9 numbers you encounter.
Following this method, and returning to the narrative, if you were to log out your user would be marked as logged out resulting in both yourself and your S/O being required to reauthenticate. (assuming you've changed your password you're golden, otherwise it's time to contact Customer Support)
If you were to log back in, you'd get a fresh JWT and a new signature would be stored in the Users table. If your S/O were to try to use the site, they would not be authenticated with the their old JWT and would be forced to sign back in.
Trade-off: If we only store the JWS, or a part of it as I suggested, multiple users can't be signed in to the same account at once. How you feel should feel about that really depends on your app.

How access token is validated for accessing protected resources in token based mechanism?

I want to do token based mechanism where I would be having either SPA or mobile apps supporting multiple clients.
Use case of my web service engine and my application:
My web application: Client will do registration of their application either SPA or mobile apps.They will get client id on registration.Only client id as secret key would be compromised in case of SPA or mobile apps hence I am just providing clientid.
Web service engine: Support multiple client with managing session of each user after login in to respective application of clients.
So let's say there are 2 client who have register their application in to my web application :
Client 1 : MyApp1
Client 2 : MyApp2
Now if MyApp1 have 2 users with John and Stephen and if they login in MyApp1 then i want to manage session for those users with token based mechanism. Now if John and Stephen wants to access protected resource then they can access only through valid accesstoken.
Same goes for MyApp2.
For token based mechanism I have seen lots of question referring to this below article only:
http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
But the only confusion part in above tutorial and in most of the tutorial is after validating user name and password and generating access token. Does above tutorial is storing access token in server side cookie for validating accesstoken when request comes to access protected resource?
I am really confused here. I know accesstoken validation happens inside [Authorize attribute] but I am not getting without storing accesstoken how above tutorial is validating accesstoken.
My thought is like may be when request comes for accessing protected resources access token is encrypted or decrypted based on machine key attribute in webconfig and this is how access token is validated inside [Authorize] attribute but I am just not sure about this.
You can control what information goes inside a token. Look at the SimpleAuthorizationServerProvider class in the article:
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
Use the Claims to store anything you need regarding to the user, their username or roles and this is what happens in the article you referred to.
The token generated already contains that information about the user.
This is taken from the article :
The second method “GrantResourceOwnerCredentials” is responsible to
validate the username and password sent to the authorization server’s
token endpoint, so we’ll use the “AuthRepository” class we created
earlier and call the method “FindUser” to check if the username and
password are valid.
If the credentials are valid we’ll create “ClaimsIdentity” class and
pass the authentication type to it, in our case “bearer token”, then
we’ll add two claims (“sub”,”role”) and those will be included in the
signed token. You can add different claims here but the token size
will increase for sure.
This is why you do not need to store the token anywhere,the token is self contained and everything is stored inside it in an encrypted form. Don't forget that before you add a claim containing the username you have already validated the username and password, so you can guarantee that the token is created correctly for a valid user / password combination. Of course you do not want to store the password inside the token, the whole point of tokens is to avoid doing that. Passing passwords to an API all the time does increase the risk of them being stolen, tokens are much better for this.
Finally, the tokens expire after a time you control, usually they are short lived so even if someone does get their hands on one they will not last long.
If you take care of how you pass the tokens, meaning in the Authorisation Header over an https call then you are as protected as you can be and the headers will be encrypted. The point here is to never issue calls like this over basic http.
The author of the article you referenced is a well respected authority in this particular area and currently a Microsoft MVP and you are basically in good hands. Keep reading his articles, but pay attention to the details.
----------- Clarification related to JWT format --------------
yes the JWT token will contain information related to its issue date and expiry date as well. I have an article of my own on this : https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/
Look at the calls which create the token and look at the information returned in the screenshots.
In my example the token contains the actual encrypted token, the token type, seconds it expires in, the audience which is the ClientID, when it was issued and when it expires.
This is just an example of a token, yours will look probably a bit differently but you get the idea I hope. Use Postman to see what's coming back in the token
There are a number of concepts to be understood when it comes to OAuth2, it does require a bit of research and practice.
In short, you request a token with A Basic Authorisation Header, you get the token back and it's telling you what type it is, in my case it's Bearer so that's my next Authorisation Header for any call to a protected resource.
My suggestion is to start small, one step at a time, use Postman to build your calls and understand what's going on. Once you have that knowledge it's much easier to progress. Took me about 6 weeks to wrap my head around all concepts and get something working first time around, but now it takes a couple hours at most. Good luck
The application does not need to store the access token server side, it will only read the user from the token which is passed along.
When the request hits the authentication server, which is attach to the Owin pipeline in the ConfigureOAuth() method,
the HTTP header token is decrypted and the user data from the token is sat to the current user of the context.
This is one of the things that bugged me for a long time
I'm not sure I understand why did you give an example for 2 applications, but the token mechanism is actually simple, but it's kinda black boxed when you use owin and identity
the token is not stored anywhere on the server or the database, authenticating the user on login is done using your logic or usually again black boxed in identity, this involves validating a secured password etc
after this the token is generated (usually using identity) or if you did it manually this will involve securing the token with whatever info you want to store in it
when the user sends a request next time he should pass the token and you will need to decrypt it and validate what's necessary (like expiration time for example), all of this is done behind the scene usually
just a fun note: even if you changed the DB completely the token will still be valid with the user id that doesn't even exist in your new DB! but of course identity automatically invalidates this token when it compares with the securityStamp

Creating a secure temporary access token for user login, is this good enough?

Ok so I am creating an API for manipulating users and data in a web application using XML. If they POST XML they can create users, etc. I am using a 2-legged OAuth solution to secure and verify the API requests. However this question is not about that aspect of security, but the aspect I will describe is for allowing the user to login from an API request without having to type their username and password, here is what I have:
Step 1, partner uses XML API to create a user, if successful the system returns a path containing the new ID, "/user/99" for example.
Step 2, partner makes a request to user/login/99, this will create a new "Login Token" in my database, here are the relevant properties:
UserID int FK
AccountID int FK
Token string
Expiration date
Used bit
UserID and AccountID are related to the respective Users and Accounts table...
the Token is the first 20 characters of a randomly generated GUID with the dashes removed and all characters set ToUpper().
The Expiration is 30 seconds from DateTime.Now.
Used = false
Step 3, the partner will have knowledge of the URL of the system (which is on a different domain from the API), and they can now make a POST to it like this:
http://otherdomain.webapp.com/core/login/[insert guid here]
Now, the 'otherdomain' part is going to be unique per account, so at this point we verify:
Look up the LoginToken based on the provided guid, if it goes with the account that matches the subdomain, is NOT expired (within 30 seconds), AND 'Used' is set to false still, log the user in, set Used = true, direct them to the homepage or to another URL if one was provided via querystring.
So basically you NEED a complete registered App and secret key and all the jazz for OAuth simply to REQUEST the GUID which allows you to login but only works ONE time and within a 30 second window... and they need to have knowledge of the login URL in the first place, IS THIS GOOD ENOUGH?
In the end if someone can somehow know the GUID and the URL all within 30 seconds they could hi-jack the login, but what are the chances of that?
Alternatively, what could I add to make it more secure?
(Disclaimer: I am not a security expert.)
The immediate problem that I notice is this:
http://otherdomain.webapp.com/core/login/[insert guid here]
Based on your setup, the GUID token has to be given to the user when it's requested. That's effectively the password for the request. If you send it over HTTP, anybody who can snoop the connection has the token and it wouldn't be hard to hijack the session. This absolutely must use SSL for the entire process.
Beyond that, the problem is that you're sending the token to the user before they can use it, which isn't great. But with SSL it may very well be good enough for your purposes. I've used a similar method when dealing with a protocol that can't handle normal authentication, the user connects over the secured channel first and says "I want to do a transfer on the other one", and the server sends back a token they can use for that request. It works well enough on a low-security system. If you're protecting critical data, I'd strongly recommend you invest the money to bring in an expert to look at it before going to production.

Categories

Resources