I'm currently working on authentication and authorisation with Angular and .NET Core. From what I've read on various posts on SO and from the IdentityServer and Auth0 docs is that a refresh token should not be used with a SPA - I understand the reasons why, no explanation needed here.
What I don't understand is why stealing a refresh token is any different to stealing a cookie?
There are some options (SameSite, HttpOnly) supported by browsers making stealing a cookie hard to perform. Tokens stored in a browser do not have such protection for today. Briefly that's it. You can find deeper comparison here
Related
Hi guys I'm recently building a web app, which is basically a shopping site. Security is one of my major concerns. I'm gonna use JWTs (access token & refresh token).
I'm gonna implement it this way: the server will return both access token and refresh token to a logged in user. And for the front end, I'm using React, so I'm gonna save the access token(short lived) in memory(like React context). I'm thinking about store the refresh token(long lived) in cookie, so I'm wondering is there a way for a hacker to extract the cookie and then use it on some clients like Postman and send requests to get access token and write some Javascript to get the access token?
Maybe think of keeping both of these tokens in memory? If you want your user to be still logged in when they come back to your application, you can rely on an SSO session that will log them in seamlessly, instead of using a refresh token in the background.
Have a look at these SPA security best practices. Also I would recommend not to use JWTs as access and refresh tokens, so that no one can read the data that is kept in your JWTs. You can use Token Introspection in your APIs or implement a Phantom Token Approach instead.
Have a look also at this document by W3C which gives some guidelines on security settings you can use for your application.
Your question does not sound stupid at all! It is a great question. There is a way for a hacker to extract the cookie yes. Cookie stealing is a known security issue.
However the way to stop this issue is by enabling CORS that blocks any cross origin API manipulation. By doing this you create a whitelist enabling your web app's URL.
I would recommend disabling this on your development server to enable localhost for faster development, and then enabling it on production.
Here is some starting documentation on CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Happy coding!
We are developing an application that uses a React front end website hosted on AWS using Amplify. This communicates with a .NET Core 3.1 Web API running on EC2 / Elastic Beanstalk. Cognito is used for user authentication with the Web API configured to use JWT tokens.
It works OK, but we have noticed that the Cognito provider stores the JWT access token in the browser local storage. This is what we see using F12 in Chrome and inspecting local storage.
From what we have read, storing access tokens in local storage is not advised as it makes the application susceptible to XSS attacks. Strange then, that the Cognito identity provider chooses to store sensitive information here.
If this approach is not considered safe, can the provider be configured to store this information elsewhere, such as cookies?
Alternatively, as we control both front and back ends, is there an alternative method that can be used to secure the API that does not involve tokens? Obviously the API needs to know which user is logged on to the web application in order to perform authorization checks. [Note authorization in the application is record level and defined in database tables, so it goes beyond simple user profile attributes.]
Many thanks in advance for your advice.
Doug
Security is a spectrum not a feature so it really depends on your appetite for risk vs effort. Amplify is not a particularly nice codebase, it has 500+ issues and if you look at the code you might be fairly shocked at the quality of it.
If you are using Hosted-UI then you can write code to manage the tokens yourself rather than using amplify, although you will need to learn a bit about OAuth grants and OIDC.
Be aware that the Hosted UI lacks a huge amount of features, so if you are going to use it make sure you are happy with it. Off the top of my head
no silent refresh capability in the hosted UI, so no safe way to store the refresh token.
no support for custom auth flow in the hosted UI
no passwordless support in the hosted UI
no ability to pre-populate a field in the hosted UI (e.g. username)
no ability to customise the plethora of obscure error messages in the custom UI
fixed now, but for years the email addresses were case sensitive!
An alternative is also to just use the AWS SDK to get tokens directly using cognito-idp but this also has a bunch of issues:
no code/PKCE/nonce capability so insecure in a mobile authsession
no ability to set oauth scopes, so can't use them
consequently not possible to use for OIDC
the SRP implementation is bananas and so far off spec
if you make device registration mandatory, it will deliver a working access tokens before the device is registered! (allows invisible devices for malicious logins)
We were using auth0 which was leagues ahead but we had to move to Cognito because of SMS OTP cost (min $25k per year at auth0).
I have been using AWS for over a decade now, Cognito is by far the worst service I have used, and I have used a lot! If you can avoid it, do so.
To answer the original question, yeah it's insecure. The best you can probably do is keep them in memory. If you wanted to you could probably put the hosted UI behind a cloudfront and use an lambda#edge to transform the token into a cookie instead. This has now opened you up to CSRF attacks though.
answering the original question: no, it is not safe at all.
Storing refreshtoken in any local storage accessable to any local app/script is not secure. So, the best way would be to store the refreshoten (and also the access token) in an httponly cookie or even better to store a one-time session token in httponly secure cookie could be used to get new access and refresh cookies - similarly as it is made by cognito hosted ui with XSRF-TOKEN.
See below how I would solve (and plan to solve) this issue:
Some background:
Due to GDPR regulations I think I can not use the cognito hosted ui - I have to make sure users read and accept the general terms and conditions (giving clear and auditable consent) and can review and accept cookie policies as well before they type in any user data for sign up. Nevertheless the built in hosted ui design is quite outdated and unflexible. I have an SPA website where I want to manage users, secure endpoints, etc.
So I have the following idea which is still not super secure but I think it is more secure one if you want to use js and ampify sdk and which also might answer your question:
I'll use amplify javascript sdk to let users sign up, change psw and log in (get tokenid, access token and refresh token), will make my own "hosted ui". I'll store the access token in memory only (not in local cookies and not in localstorage for sure). Access token will be used in header (bearer) to access apiGW endpoints. Access tokens will have very short expire dates. (I'd also use httponly secure cookies sent back by the apigw, as well as in the body.., then compare at BE side..)
And here comes the trick: I'd cut the refresh token into two. (Don't forget it is just a string.) I'd store the first part of the string in a local cookie (javascript can read it, if browser is closed and opened again it will be still there) and will send the other half of the refresh token to an apiGW endpoint (accessable without authentication) which will store it in a dynamoDB table (with TTL) and will send back an httponly secure cookie to the browser with a randomly generated "storagetoken" in it (which will be a key in dynamodb). There will be another unauthenticated apigw endpoint which will be called by the client whenever the client needs the full refresh token. Calling this endpoint the browser will send in the httponly secure cookie as well (same domain), so the backend will get it. As it is issued by the BE and available only in the given browser it can not be stolen so the backend will send back the stored half refreshtoken. The other half part of refreshtoken is stored in a simple cookie in the browser.
If the browser is closed and opened again client checks if there is any valid accesstoken and if not it checks if there is a half refeshtoken stored as cookie. Then ask the other part of refreshtoken assuming there is a httponlycookie also stored and it will get back the other part of the refreshtoken from the BE. In case of success the client tries to use the full refreshtoken to renew/get access token from cognito, in case of failure it will pop up the login screen.
Whenever refreshtoken is not in use it is deleted from the memory.
I know this is still not supersecure but might be a better solution than storing refresh token in localstorage.
Alternatively, as we control both front and back ends, is there an alternative method that can be used to secure the API that does not involve tokens?
I don't know anything of Amplify but in AWS Cognito what you describe is the Implicit grant OAuth flow. In AWS Cognito it is possible to use Authorization code grant where you instead of the token get a code which you in the backend can exchange for a user pool token.
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-configuring-app-integration.html
What is an appropriate secure way to use OAuth 2.0 with SPA applications and Native Apps?
I have seen conflicting opinions in stack overflow and vendor documentation on whether OAuth refresh tokens should be stored in the browser for SPA's and in Native Mobile Apps.
For example here I have 3 links, one of them IETF including receiving refresh token in the App. While several others including auth0 recommend against receiving refresh token on the client side.
https://www.pingidentity.com/en/company/blog/posts/2018/oauth-recommendations-for-single-page-apps.html
https://tools.ietf.org/html/bcp212
https://community.auth0.com/t/obtaining-refresh-token-along-with-access-token-in-a-spa/6476
https://developer.okta.com/docs/api/resources/oidc
They are different answers.
For SPA, the Authorization Code flow without sending client secret is used ( check Arron Parecki's blog posts on the subject ). As a fallback, the implicit flow is less secure but can also be used if you understand the risks.
For mobile native, the best practice is Authorization Code flow with PKCE ( pixie )
https://developer.okta.com/blog/2018/12/13/oauth-2-for-native-and-mobile-apps
I am currently developing a small application with a couple of endpoints in nodejs and an angularjs frontend.
At the moment I have an endpoint for users and another one for events. The thing is, I was thinking of making all the GET methods require auth, so that someone that isn't logged in can't access the system, for that I thought of using PassportJS.
Anyways, my question/s would be the following:
What auth strategy should I use? Basic, OAuth or another? Why would that be? I mean, I understand how their flow works, but I don't know why one or another would be appropiate for my app.
Should the endpoints require auth or should it check cookies/token or something else in the session? I'm completely new to this, so I don't even know if this question makes sense.
In any case, I would appreciate any overall insight in the topic since I don't have any experience in developing applications with auth and security.
Thanks!
You have to provide more details about your authentication needs in order for someone to give you a definitive answer to this broad question.
Based on your question, one can assume you don't have any requirements though, therefore I could suggest JWT (JSON Web Tokens - https://jwt.io/)
There are nodejs libraries that can help you create, decode, verify JWT tokens. (such as jsonwebtoken). You can find more details about it on github.
Once someone is logged in, you could pass this generated token back to the client which could store it in the browser's session.
The token can be used in subsequent requests by appending it in the request header.
On the server side, you can add a custom auth middleware to the routes that require authentication, which will verify the token's validity and call the next middleware for the current route.
I am having problem implementing Google Plus Web Server authentication
https://developers.google.com/accounts/docs/OAuth2WebServer
I have implemented most of the steps, until the last step, I have no idea how to make a callback with token to my Angular.JS,
I found an article which solves my problem (and it has the same implementation as mine):
http://apicatus-laboratory.rhcloud.com/2014/04/13/handling-oauth-callbacks-in-spa/
But, I have few questions for this article,
is this way legit??? or any other security flaws that I need to consider?
what is the normal way to do it? if I dont want to use Google SDK, cookie and session to send the token back to my Angular, what other possible ways to send token to my Angular app?
how the normal angular app handle the callback?
Why not use this flow that is meant for javascript applications?
https://developers.google.com/+/web/signin/javascript-flow
& https://developers.google.com/accounts/docs/OAuth2UserAgent
You can get an id_token (it is JWT) directly from Google in JS and use that.
What the article is trying to do is to get the Google Oauth response to the server and issue it's own JWT just like any site would issue its own authentication cookies and use those in the application.
Both are possible options depending on the goal of your application.