We are creating an Asp.NET MVC-5 application with Identity, and the database is accessed through a WebAPI using OAuth2. When a user logs in with a username and password, the MVC application uses this info to log in to the WebAPI to request the first access_token and refresh_token. These tokens are stored in the MVC application in a dictionary with the user's username as the key. The tokens are not exposed outside of the MVC Application. We then use the user's username to retrieve the tokens from the dictionary each request that the user makes.
We use Identity with Cookie Authentication in the MVC Application. The MVC Application is going to restart every once in a while (every week or so), which means we'll lose the access and refresh tokens stored in memory.
My questions:
We use the UserName provided by User.Identity.Name as the key to retrieve the user's access_token and refresh_token from the dictionary. Is this safe? I assume Identity retrieves this from the cookie. Would it be possible for a user to change the cookie to pretend to be another user, or is Identity's serialization safe enough?
I plan to store the refresh token in the cookie as well, so that when the MVC application has restarted, we can use this token to authenticate the user without forcing the user to log back in. This is basically the same question as 1. Is this safe?
If both are in fact not safe, would it be sufficient to create a small local database where we store this data, and use a GUID in the cookie to retrieve it? We're trying to avoid needing a local database, but if it's necessary then so be it.
Thanks for the help.
It's not secure to store the refresh or access tokens in cookies.
Please refer to Where to store access and refresh tokens on ASP.NET client web app - calling a REST API
You shouldn't be concerned about "losing the access and refresh tokens stored in memory". If it happens, just recreate them.
BTW: Storing any user data at in-memory dictionary is not a good idea. Use ASP Session management. It would be much easier to add any backed to that (in-proc, database, redis).
Related
Currently I have this setup:
At login, and in every subsequent request after login, a mobile application that I have built uses Basic Authentication to authenticate the user with a web service that serves the app with information it requests.
On every request the Authorization header is inspected, the password and username are extracted from the header, the password is hashed using a proprietary DLL (so the web service doesn't actually contain the hashing algorithm) and compared to the hashed password associated with the username that is stored in the database.
I have now been asked to include Azure AD SSO in the login options.
After reading much about the topic, this looks seems to me like the setup:
I'm curious about a few things:
Is this setup correct, more or less?
Does the app send the Identity Token to the web service? If so, how does the webservice validate that token?
Is it correct that the webservice can match the Azure Identity to the DB user using one of the claims in the Security Token?
Where do Access Token fit in this picture?
Thanks for the help!
(Side Note: I know that Basic Authentication is not the preferred way to go in the first scenario. This was a temporary decision till we developed the token handling code, it only works using HTTPS and this is an internal application - you wouldn't be able to activate the app unless you have a code we give you)
I have little experience in azure ad but I think we could talk about your case.
First, whatever id token and access token are both jwt token, so to your web service application, you need to use jwt decode library to decrypt the token and get claims it contains. Here we need to know the difference between id token and access token, and I think you'll know that for your web service application, if it's more likely to play the role of an api application, you need to use access token because this token also contains user information. Then you need to add code in your program to decode the token and check if it's a 'valid' token for the request.(Because you've used azure ad to achieve the login part, you don't need to use your custom login part.)
Next, the signing in feature provided by azure ad requires to use account and password in the tenant which azure ad belongs to, the user accounts may look like xx#xx.onmicrosoft.com, it doesn't required to keep sycn with the accounts in your database, so it's difficult and needless for you to compare the user name obtained from the decoded token with those in your database. Because when your web service received the token(id or access token), that means someone has passed the authentication from azure ad. The token contains user information including role, expired time etc. You need to check if the token has expired and if has the correct scope. (Let's see a common situation, microsoft provides many graph apis to call, when accessing these api, we need to provide access token in request head with matching scope, e.g. https://graph.microsoft.com/v1.0/me
requires a delegated api permission of User.Read)
To sum up here, if your web service just required the users in your database to sign in then can be access, id token and access token are both suitable for you because they both contains user name like 'xx#xx.onmicrosoft.com', what you need to do is decode the token and check if the token has expired and whether this user exists in your database(you may set up a mapping between them).
I currently use Spring Oauth 2 framework for authentication and authorization. When i google on what is the best way to store the access token and refresh token, i was recommended to store the access token in memory such as a variable and store the refresh token in a secured HttpOnly cookie. This was working fine until i faced a new issue.
I opened a new tab next to the tab where i was already logged in, now the problem is instead of directly going into the application, the login page was presented. I now again enter my username and password and login into the second tab without any issues.
But when i do logout from the 2nd tab, both first and second tab gets logged out since the refresh token cookie is shared but the access token which is not shared between tabs since its stored in a variable.
I was expecting following results
When i do a login into my second tab, i expect the session to be separate. The reason i'm setting the refresh token in cookies instead of storing it in a variable like access token because there are multiple applications hosted in the same domain to implement SSO concept. When an another application is clicked instead of routing it to a login page, i just get a new access token for the application using the refresh token that is stored in the http only cookie
I was told the only solution is to store the access token in localstorage or normal cookies so that i can also share the access token between tabs but it seems to be not a secure way as the token being can be stolen using XSS attack.
Hoping for a optimal solution. BTW when the user logsout, the invalidate both the access and refresh token from my JDBC token store
Sounds like you need to decide what type of Web UI you want. Trying to mix and match these concepts does not work well, as you are discovering:
Either your Web UI is a cookieless Single Page Application
Or your Web UI routes all data requests via a web back end using an Auth cookie
TOKEN SCOPE
Generally tokens are private per browser tab and auth cookies are not, as you realise. Using tokens in the Web UI will give you better control of usability aspects.
SPA COOKIELESS MODEL
This gives you independent sessions per browser tab, but requires you to use a library such as oidc client to implement logins client side. You can then store an access token in memory. Token refresh is done via silent iframe redirects and not via refresh tokens.
SPA COOKIELESS COMPONENTS
In this model:
Spring Boot's role would be to host REST APIs
The Web UI would not use Java at all
The Web Back End would be just static content
For a bit more background, and how to implement login / token management in Javascript, see these posts of mine:
SPA Goals
Tutorial + Code Sample
NO WEB UI OPTION IS PERFECT
They all have annoyances and sometimes it depends what your stakeholders most care about.
I have an ASP MVC 5 app. The app talks to a WCF service. Once the user has passed in their credentials, a connection to WCF is established using those credentials. This is done so that the WCF services restricts their access and only returns useful data to the MVC app.
Authentication is working correctly, and the WCF credentials are stored for the session. However, if I shut down the app, and start it up again, these credentials are lost. So, my question is, what is the best approach to storing the credentials?
If I persist the credentials to file, I probably should encrypt them right? Is there some recommended way of storing passwords so that I can later decrypt them? If so, wouldn't this be very insecure because anyone on the server can grab user's passwords and decrypt them?
Lastly, just to confirm, the cookie on the client side doesn't save and resend the password does it? Just so I understand this correctly, the cookie is just a unique identifier that confirms that the client has previously been talking to the server. Right?
I'm trying to add authentication feature to my application.
The authentication server implements oauth 2.0
I'm not sure how to save the refresh_token. I want to save it to a file, so next time when the application starts and there is a refresh_token available, it can ask for a new access_token. The user won't need to re-login again.
But this doesn't sound secure to me, because if someone copies my file that has the refresh_token to another computer, he can hack into my account.
You are correct with the attack that you describe. Refresh tokens have to be stored securely in order to be used as intended. As I understand, you are building a standalone application. Therefore, you can rely on file system security to prevent a refresh token being copied by an unauthorized user. You may want to use encryption for the refresh token, too, but the key would need to be bound to a user's session at your local machine (otherwise, the user would need to provide it during "sign in" process in order for the application to decrypt the refresh token).
Consider reading the thread from the OAuth WG, that discusses similar problems to the one described and provides some guidance:
https://www.ietf.org/mail-archive/web/oauth/current/msg02292.html
Refresh tokens are used to obtain access (this process requires HTTP Basic Auth). So, unless user has your (id,secret) combination he can't do much about it. However, storage of refresh token must be considered very seriously.
Here's my two cents:
Store your tokens in a DB
Whenever you use refresh token to obtain access token reset the refresh token as well. (Oauth2.0 has this feature, you can let the refresh token unchanged too, but it's wise in terms of security perspective to keep it changing and updating the DB)
Hope this gives some insights!!
You are right about your concern - you should not save the refresh token. By doing so, you jeopardize your client's data (and you know the reason; you wrote it in the question).
oAuth is not supposed to work this way.
You should keep the refresh token in-memory.
I'm currently working on a project where an iPad application requires access to an existing web application. The iPad application has been developed internally and is therefore a trusted application. However the data provided by the web application is sensitive so we don't want to store client credentials on the iPad. We also want the ability to revoke iPad access without affecting regular user access.
Given the above, the OAuth2 Resource Owner Password Credentials grant/flow was a good fit for our requirements which we've implemented with DotNetOpenAuth since its an established library.
However, we now require some metadata to be added to the access and refresh tokens for the resource server. The authorization server is adding the metadata via the AuthorizationServerAccessToken.ExtraData property in our implementation of the IAuthorizationServerHost.CreateAccessToken method:
public AccessTokenResult CreateAccessToken(IAccessTokenRequest accessTokenRequestMessage)
{
var accessToken = new AuthorizationServerAccessToken();
// Add some extra data to access token
accessToken.ExtraData.Add("server_parameter1", this.ServerValue1);
accessToken.ExtraData.Add("server_parameter2", this.ServerValue2);
// Set ResourceServerEncryptionKey properties etc
return new AccessTokenResult(accessToken);
}
This does exactly what we want for the access token however the same "ExtraData" is not included in the refresh token which causes an issue when the access token expires and needs to be refreshed because we effectively lose the additional data (since the old access token is discarded).
Can anyone advise if its possible to populate the refresh tokens "ExtraData" in the current version of DotNetOpenAuth in a similar way to the access token?
No, I don't think there is currently a way to embed extra data into the refresh token. Let's talk a bit about why this is.
First off, there is no such thing as a trusted iPad app, whether you develop it or not. The problem is that apps you distribute (even internally) can't keep a secret. Any client_secret, certificate, etc., can be cracked. Therefore apps you distribute can't authenticate themselves to the server. If the server can't authenticate the client, the server can't trust the client.
Now let's look at your scenario a bit more (and if you have more feedback, it may be best to continue the discussion on dotnetopenid#googlegroups.com). The client has data that it wants to eventually end up at the resource server. You're currently trying to pass that data through the authorization server first, then via the access token to the resource server. Why is that? Why not just have the client send the data directly to the resource server along with the access token? If the answer is that the resource server shouldn't trust the client, then what you have by sending it by way of the access token is a false sense of security for the reasons given in the above paragraph. If the client could provide false info to the resource server, it could also provide false data to the authorization server.
One valid use of extra data in the access token is data that the authorization server knows for itself -- not data that came from the client. In which case, it can look up that data each time an access token is minted and doesn't therefore have to be stored in the refresh token.