diff --git a/setup.sh b/setup.sh
index 8a7f73ea68964059930253a7f258a7648fe2900c..54bc43c82c277baee0f740a3e1555b852480c602 100755
--- a/setup.sh
+++ b/setup.sh
@@ -2,7 +2,13 @@
 
 TOKEN="$1"
 
-curl -H "x-authentication: $TOKEN" -X "POST" -d '{"num": 10, "name": "foo", "email": "foo@example.com", "password": "foo", "balance": 10000}' localhost:8080/api/member
+# set up members
+curl -H "x-authentication: $TOKEN" -X "POST" -d '{"num": 900, "name": "admin", "email": "admin@example.com", "password": "admin", "role": "admin", "balance": 10000}' localhost:8080/api/member
+curl -H "x-authentication: $TOKEN" -X "POST" -d '{"num": 901, "name": "socia", "email": "socia@example.com", "password": "socia", "balance": 10000}' localhost:8080/api/member
+
+# set up products
 curl -H "x-authentication: $TOKEN" -X "POST" -d '{"code": 234, "name": "aceite", "price": 1700, "stock": 35}' localhost:8080/api/product
-curl -H "x-authentication: $TOKEN" -X "POST" -d '{"code": 120, "name": "alubias", "price": 200, "stock": 20}' localhost:8080/api/product
-curl -H "x-authentication: $TOKEN" -X "POST" -d '{"code": 302, "name": "esparragos", "price": 300, "stock": 15}' localhost:8080/api/product
+curl -H "x-authentication: $TOKEN" -X "POST" -d '{"code": 120, "name": "alubias", "price": 200, "stock": 60}' localhost:8080/api/product
+curl -H "x-authentication: $TOKEN" -X "POST" -d '{"code": 302, "name": "esparragos", "price": 300, "stock": 45}' localhost:8080/api/product
+curl -H "x-authentication: $TOKEN" -X "POST" -d '{"code": 320, "name": "limpia suelos", "price": 450, "stock": 40}' localhost:8080/api/product
+curl -H "x-authentication: $TOKEN" -X "POST" -d '{"code": 112, "name": "arroz", "price": 120, "stock": 50}' localhost:8080/api/product
diff --git a/src/App.js b/src/App.js
index 6a867f81bf8e82d5d0a4f53950641e081ad76cb3..4dc3b81acb8ba07363e55fc2d7dd8f3a90d2bc52 100644
--- a/src/App.js
+++ b/src/App.js
@@ -36,6 +36,16 @@ function Panel(props) {
     );
 }
 
+function getClaims(token) {
+    const base64Url = token.split('.')[1];
+    const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
+    const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
+        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
+    }).join(''));
+
+    return JSON.parse(jsonPayload);
+}
+
 class App extends React.Component {
     constructor(props) {
         super(props);
@@ -55,6 +65,18 @@ class App extends React.Component {
             const num = localStorage.getItem("num");
             const role = localStorage.getItem("role");
             this.setState({ num, role, token });
+            if (getClaims(token)["exp"] !== undefined) {
+                this.timerID = setInterval(
+                    () => this.renewToken(),
+                    60000  // every minute
+                );
+            }
+        }
+    }
+
+    componentWillUnmount() {
+        if (this.timeID) {
+            clearInterval(this.timerID);
         }
     }
 
@@ -71,9 +93,18 @@ class App extends React.Component {
             token: token
         });
         this.storeState(token, member.num, member.role);
+        if (getClaims(token)["exp"] !== undefined) {
+            this.timerID = setInterval(
+                () => this.renewToken(),
+                60000  // every minute
+            );
+        }
     }
 
     logout() {
+        if (this.timeID) {
+            clearInterval(this.timerID);
+        }
         this.setState({
             num: null,
             role: null,
@@ -86,21 +117,31 @@ class App extends React.Component {
         if (!this.state.token) {
             return false;
         }
-
-        const token = this.state.token;
-		const base64Url = token.split('.')[1];
-		const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
-		const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
-			return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
-		}).join(''));
-
-		const claims = JSON.parse(jsonPayload);
+        const claims = getClaims(this.state.token);
         if (claims["exp"] === undefined) {
             return true;
         }
         return claims["exp"] < Date.now()/1000;
 	};
 
+    renewToken() {
+        fetch("/api/token")
+            .then(response => {
+                if (!response.ok) {
+                    throw new Error(response.status.toString()+' '+response.statusText);
+                }
+                return response.json();
+            })
+            .then(data => {
+                const token = data.token;
+                this.setState({token});
+                localStorage.setItem("token", token);
+            })
+            .catch(error => {
+                console.log("Error renewing token: " + error.message)
+            });
+    }
+
     render() {
         let component = <Panel onLogout={this.logout} />;
         if (!this.isLoged()) {
diff --git a/src/SignIn.js b/src/SignIn.js
index fe4d28bea654ea2453e4987800fbdb09f4a73a06..0a80d07c4f2f05ce06fff466c51362ba0b3e782f 100644
--- a/src/SignIn.js
+++ b/src/SignIn.js
@@ -46,7 +46,7 @@ class SignIn extends React.Component {
                 if (error.name === "bad-auth") {
                     this.setState({isLoading: false, error: null, badAuth: true});
                 } else {
-                    this.setState({isLoading: false, error: error})
+                    this.setState({isLoading: false, error: error.message})
                 }
             });
     }