As you know, nuxtjs is server side rendering and there is no good example how to store data into localstorage which is client side.
My work is need to build login form where user can put username and password into the form the send it to server (via api) to check, if login data is correct, the api will return one token key then I will store this key to verify is user is authen and use it with other api.
I found some example but build with vuejs here https://auth0.com/blog/build-an-app-with-vuejs/ but I don't have an idea how to change it to nuxtjs.
Any I have read https://github.com/robinvdvleuten/vuex-persistedstate which I can plug in to my project but I would like to see other solution.
Regards.
Nuxt provides you with process.client to tell it to execute only on the client side
so use it like this:
methods: {
storeToken(token) {
if(process.client) {
localStorage.setItem("authToken", token)
}
}
}
Check this link for more info.
You can use process.client to check it's on client-side or not.
export default {
created() {
this.storeToken();
},
methods:{
storeToken(token){
if(process.client){
localStorage.setItem("authToken", token);
}
}
}
}
You also call this method in mounted without check process.client.
export default {
mounted() {
this.storeToken();
},
methods:{
storeToken(token){
localStorage.setItem("authToken", token);
}
}
}
A little late to the party, but I was having similar problems.
But first I would recommend you to use cookies for saving a key/token/jwt.
The reason being that localStorage can be hijacked through JS api's and cookies can be safeguarded from that. You will however have to safeguard your token from CSFR.
That can be done by having a look at the Refence and Origin headers server side.
This guy wrote a good post on how to do that: How to protect your HTTP Cookies
As for accessing localStorage from Nuxt, here we go:
If you are running Nuxt and haven't told it to run in spa mode it will run in universal mode. Nuxt defines universal mode as:
Isomorphic application (server-side rendering + client-side navigation)
The result being that localStorage is not defined serverside and thus throws an error.
The give away for me was that console logging from middleware files and Vuex outputted to terminal and not the console in developer tools in the browser.
if you want to read more about my solution you can find it here: localStorage versus Nuxt's modes
If you plan on storing small amounts of data, below 4096 bytes, you can use cookies. I recommend the library cookie-universal-nuxt.
npm install cookie-universal-nuxt --save
nuxt.config.js
modules: [
'cookie-universal-nuxt',
],
Then you can use:
const data = {
anything: 'you want',
}
this.$cookies.set('thing', data, {
path: '/',
maxAge: 60 * 60 * 24 * 7
});
this.$cookies.get('thing');
Read the library docs for more if you need it.
The cookie will be available server-side, so you can get around the issues with localStorage.
Just be aware that cookies can only store up to 4096 bytes per cookie.
For example, I fetch cookie data in the nuxtServerInit function in Vuex, and the data is then available everywhere in the app server-side.
Insofar as client means a web browser, all the options are spelled out in the []HTML Living Standard Web Storage section.
12.2 The API
12.2.1 The Storage interface
12.2.2 The sessionStorage getter
12.2.3 The localStorage getter
12.2.4 The StorageEvent interface
U can work with const page = useState( () => data ) or if u want to use local or session storage u can use VueUse module..
I know its a bit late and it might not be the answer you are looking for...but it could be helpful for someone..what i learned after going through many documentations and other answers is that u just cant use local or session storage. In development it just runs when u change the route but when u refresh the page or the component using session storage it throws error "sessionStorage is not defined"..if u are not planning to store data for long time like u do with session or local...u can work with useState( () => data ) property that nuxt provides..it stores your data until u refresh your webPage...
Related
I am using PouchDB and CouchDB in an ionic application. While I can successfully sync local and remote databases on Chrome and Android, I get unauthorized error on Safari / iOS when I run the sync command. Below is a simplified version of my database service provider.
import PouchDB from 'pouchdb';
import PouchDBAuthentication from 'pouchdb-authentication';
#Injectable()
export class CouchDbServiceProvider {
private db: any;
private remote: any;
constructor() {
PouchDB.plugin(PouchDBAuthentication);
this.db = new PouchDB('localdb', {skip_setup: true});
}
...
login(credentials) {
let couchDBurl = 'URL of my couchDB database';
this.remote = new PouchDB(couchDBurl);
this.remote.logIn(credentials.username, credentials.password, function (err, response) {
if (err) { concole.log('login error') }
else {
let options = { live: true, retry: true, continuous: true };
this.db.sync(this.remote, options).on('error', (err_) => { console.log('sync error')});
}
})
}
...
}
In the code above, this.remote.logIn(...) is successful but this.db.sync(...) fails. I have checked the requests via the network tab of developer tools and I believe the issue is that the cookie that's retruned in the response header of this.remote.logIn(...) is not used by the subsequent calls (thus the unauthorized error). The issue is fixed once third-party cookies are enabled on Safari, which is not an option on iOS.
How can I fix this problem?
One potential solution I'm considering is overriding fetch to use native http client (i.e., an instance of HTTP from #ionic-native/http). It seems modifying http clients is a possibility (e.g., according to this conversation) but I'm not sure how to achieve that.
Changing the HTTP plumbing sounds like a really bad idea - time cost, mainly - unless you just absolutely have to use sessions/cookies...If you don't, read on.
as noted here regarding pouchDB Security, I tried using pouchdb-authentication when it was actively maintained and went another route due to multiple issues (I don't recall specifics, it was 6 years ago).
Do note the last commit to pouchdb-authentication seems to be 3 years ago. Although inactivity is not an negative indicator on the surface - a project may have simply reached a solid conclusion - installing pouchdb-authentication yields this
found 6 vulnerabilities (2 moderate, 3 high, 1 critical)
That plus the lack of love given to plugin over the last few years makes for a dangerous technical debt to add for a new project.
If possible simply send credentials using the auth option when creating (or opening) a remote database, e.g.
const credentials = { username: 'foo', passwd: 'bar' };
this.remote = new PouchDB(couchDBurl, { auth: credentials });
I don't recall why but I wrote code that is in essence what follows below, and have reused it ad nauseum because it just works with the fetch option
const user = { name: 'foo', pass: 'bar' };
const options = { fetch: function (url, opts) {
opts.headers.set('Authorization', 'Basic ' + window.btoa(user.name+':'+user.pass));
return PouchDB.fetch(url, opts);
}
};
this.remote = new PouchDB(couchDBurl, options);
I believe I chose this approach due to the nature of my authentication workflow discussed in the first link of this answer.
I agree with #RamblinRose that you might have to include the headers manually when you define the PouchDB object.
I myself have found a solution when working with JWTs that need to be included in the header for sync purposes.
See this answer. Note: RxDB uses PouchDB under the hood so it's applicable to this situation. It helped me sync, hope it does you too!
https://stackoverflow.com/a/64503760/5012227
One potential solution I'm considering is overriding fetch to use native http client (i.e., an instance of HTTP from #ionic-native/http). It seems modifying http clients is a possibility (e.g., according to this conversation) but I'm not sure how to achieve that.
Yes, this is a possible option - especially if you want to use SSL pinning which will only work with native requests. And you don't need to worry about CORS (apart from ionic serve).
You can achieve this e.g. by taking an existing fetch - polyfill and modifying it s.t. it uses the http plugin instead of xhr. And since you'll only deal with JSON when interacting with the CouchDB, you can throw away most of the polyfill.
I've got what is hopefully a very simple question about prefetching data from within an apollo/nuxt configuration.
I am requesting data from a GraphQL API and want to prefetch the data to use server-side rendering. Reading the docs it seems like I should simply be able to set prefetch: true on my apollo query but this is not working – it is always sending the request from the client side which is causing all kinds of issues.
Here is the code in my component:
apollo: {
concept: {
prefetch: true,
query: conceptStatements,
variables () {
return { id: this.$route.params.id }
}
}
}
I feel like it will have something to do with when this.$route.params.id is evaluated?
Ultimately I would like to create a Vuex store in the store/index.js which takes all of my apollo queries and renders the data in them accessible across the application but the documentation is very vague on how I might do this. Any help would be much appreciated!
Are you really sure your data is not prefetched?
Prefetch is for the first rendering (in SSR mode) ; Nuxt/Apollo call your graphql api, generate the page and send it to the browser. If you just navigate to your page from another route, nuxt call your api from the browser.
You can check this behavior in devtools/network, select xhr. Refresh your page, there is not xhr call. Go to another route and refresh your page, then navigate to your route where is your apollo query and you should see a xhr call to your graphql api.
Also, you can configure this behavior in your apollo config with fetchPolicy.
You don't need Vuex to store response of your apollo queries:
From vue-apollo doc:
When you perform GraphQL queries with Apollo, the results of API calls
will be stored in Apollo cache. Now imagine you also need to store
some kind of a local application state and make it available for
different components. Usually, in Vue application we can achieve this
with Vuex. But having both Apollo and Vuex will mean you store your
data in two different places so you have two sources of truth.
So, if your perform same query from different page or component, Apollo don't call your api each time, but retrieve data from the Apollo cache. Apollo is just magic!
I'm trying to incorporate an email verification step in the signing up process of my app. Looking at the docs online, seems like doing it in the front-end seems like the way to go.
Problem is the examples I see online have the entire sign in process done in the front-end, and just simply include the the sendEmailVerification method.
sendEmailVerification Method
firebase.auth().currentUser.sendEmailVerification().then(function() {
// Email sent.
}).catch(function(error) {
// An error happened.
});
I (instead) built my sign up method in the backend and its respective handler in the front.
Front-End Sign Up Handler
authHandler = () => {
const authData = {
email: this.state.controls.email.value,
password: this.state.controls.password.value
};
this.props.onTryAuth(authData, this.state.authMode);
// ontTryAuth is a backend action that creates new users in Firebase
};
Is it a good idea to include the sendEmailVerification method into this front-end handler code? If so, how do I go about doing it?
Yes you can use it. First this method is built by Firebase because people who use Firebase don't always/never have a server. You can yes build your own signup method in your server, but why you would use Firebase if you start to override all the stuff they give you? For me I see Firebase as a prototyping tool and so I use all the features they give, so that let me put an app working faster.
Let me know if that make sense.
Update March 2019
I just went over this question again; the Auth0's github code has been updated in December 2018. They are now storing 'access_token','id_token' and 'expire_at' into the object/session, instead of localstorage and using now an 'isLoggedIn' flag to mark if authenticated or not. Check the pull request and these 2 lines in the specific commit: line1 and line2.
If you do not need to re-validate 'id_token' - like I was doing in the original question - that might be an alternative. Otherwise check original question.
Original Question
We are using auth0 for one of our clients. One stack that we are using it for is:
React/Redux UI
NodeJS backend
So we are using a cross origin authentication using implicit grant for that, using JWT with an RS256 algorithm. We also refresh tokens in background using silent authentication.
I was able to validate 'access_token' on the API (nodejs) side using node-jwks-rsa for express
On the UI level, after going through the source code of the auth0-js library I noticed that the "parseHash" method used in their provided react samples, actually validates tokens before we store them in localstorage, ie on successful authentication. Mainly this line in the source code.
Then I used their sample code that allows us to check if a user is authenticated, method isAuthenticated().
Problem with the isAuthenticated() method
From a security perspective, if later on (post authentication) a user of the application decided to manually modify the 'expire_at' label in the storage, they could get away as indeed authenticated. While of course there is additional security checking in our app, I wanted to update this function to validate 'id_token'. So far, I couldn't find any example in auth0's online docs for how to do that.
After digging in their source code I found a method validateToken that is being used. So I decided to leverage it in one of our functions:
import IdTokenVerifier from 'idtoken-verifier'
.... Some code in here ....
reValidateToken() {
return new Promise((resolve, reject) => {
// Both of these are stored in localstorage on successful authentication, using the parseHash method
let id_token = localStorage.getItem('id_token');
let transactionNonce = localStorage.getItem('app_nonce');
this.webAuth.validateToken(id_token, transactionNonce, function(
validationError,
payload
) {
if (!validationError) {
resolve('no validation errors for id_token');
}
if (validationError.error !== 'invalid_token') {
reject(validationError.error);
}
// if it's an invalid_token error, decode the token
var decodedToken = new IdTokenVerifier().decode(id_token);
// if the alg is not HS256, return the raw error
if (decodedToken.header.alg !== 'HS256') {
reject(validationError);
}
});
});
}`
Now, for it to succeed; we store the nonce in localstorage after successful authentication, does this approach create back doors for potential security holes? if it does; what is best practice to validate RS256 JWT id_token(s) on a UI level?
Working on my first EmberJS app. The entire app requires that a user be logged in. I'm trying to wrap my head around the best way to enforce that a user is logged in now (when the page is initially loaded) and in the future (when user is logged out and there is no refresh).
I have the user authentication hooks handled - right now I have an ember-data model and associated store that connects that handles authorizing a user and creating a user "session" (using sessionStorage).
What I don't know how to do is enforce that a user is authenticated when transitioning across routes, including the initial transition in the root route. Where do I put this logic? If I have an authentication statemanager, how do I hook that in to the routes? Should I have an auth route that is outside of the root routes?
Note: let me know if this question is poorly worded or I need to explain anything better, I will be glad to do so.
Edit:
I ended up doing something that I consider a little more ember-esque, albeit possibly a messy implementation. I have an auth statemanager that stores the current user's authentication key, as well as the current state.
Whenever something needs authentication, it simply asks the authmanager for it and passes a callback function to run with the authentication key. If the user isn't logged in, it pulls up a login form, holding off the callback function until the user logs in.
Here's some select portions of the code I'm using. Needs cleaning up, and I left out some stuff. http://gist.github.com/3741751
If you need to perform a check before initial state transition, there is a special function on the Ember.Application class called deferReadiness(). The comment from the source code:
By default, the router will begin trying to translate the current URL into
application state once the browser emits the DOMContentReady event. If you
need to defer routing, you can call the application's deferReadiness() method.
Once routing can begin, call the advanceReadiness() method.
Note that at the time of writing this function is available only in ember-latest
In terms of rechecking authentication between route transitions, you can add hooks to the enter and exit methods of Ember.Route:
var redirectToLogin = function(router){
// Do your login check here.
if (!App.loggedIn) {
Ember.run.next(this, function(){
if (router.currentState.name != "login") {
router.transitionTo('root.login');
}
})
}
};
// Define the routes.
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
enter: redirectToLogin,
login: Ember.Route.Extend({
route: 'login',
exit: redirectToLogin,
connectOutlets: function(router){
router.get('applicationController').connectOutlet('login');
}
}),
....
})
});
The problem with such a solution is that Ember will actually transition to the new Route (and thus load all data, etc) before then transitioning back to your login route. So that potentially exposes bits of your app you don't want them seeing any longer. However, the reality is that all of that data is still loaded in memory and accessible via the JavaScript console, so I think this is a decent solution.
Also remember that since Ember.Route.extend returns a new object, you can create your own wrapper and then reuse it throughout your app:
App.AuthenticatedRoute = Ember.Route.extend({
enter: redirectToLogin
});
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
index: App.AuthenticatedRoute.extend({
...
})
})
});
If you use the above solution then you can cherry pick exactly which routes you authenticate. You can also drop the "check if they're transitioning to the login screen" check in redirectToLogin.
I put together a super simple package to manage session and auth called Ember.Session https://github.com/andrewreedy/ember-session
Please also take a look at :
http://www.embercasts.com/
There are two screencasts there about authentication.
Thanks.