Added storing authorization code and access token in cache; fixed bugs.

Change-Id: Ibc555ed65ebec8e7b40a76521311680a63c11a09
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/OAuth2Authentication.java b/full/src/main/java/de/ids_mannheim/korap/authentication/OAuth2Authentication.java
index ffee80a..8f5e702 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/OAuth2Authentication.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/OAuth2Authentication.java
@@ -37,8 +37,8 @@
             throw new KustvaktException(StatusCodes.EXPIRED);
         }
 
-        ZonedDateTime expiry =
-                accessToken.getCreatedDate().plusSeconds(config.getTokenTTL());
+        ZonedDateTime expiry = accessToken.getCreatedDate()
+                .plusSeconds(config.getAccessTokenExpiry());
         String scopes = scopeService
                 .convertAccessScopesToString(accessToken.getScopes());
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/http/HttpAuthorizationHandler.java b/full/src/main/java/de/ids_mannheim/korap/authentication/http/HttpAuthorizationHandler.java
index 7796345..5eed64f 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/http/HttpAuthorizationHandler.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/http/HttpAuthorizationHandler.java
@@ -1,6 +1,5 @@
 package de.ids_mannheim.korap.authentication.http;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import de.ids_mannheim.korap.constant.AuthenticationScheme;
@@ -18,15 +17,12 @@
 @Component
 public class HttpAuthorizationHandler {
 
-    @Autowired
-    private TransferEncoding transferEncoding;
-
-    public String createBasicAuthorizationHeaderValue (String username, 
+    public static String createBasicAuthorizationHeaderValue (String username, 
             String password) throws KustvaktException {
         ParameterChecker.checkStringValue(username, "username");
         ParameterChecker.checkStringValue(password, "password");
 
-        String credentials = transferEncoding.encodeBase64(username, password);
+        String credentials = TransferEncoding.encodeBase64(username, password);
         return AuthenticationScheme.BASIC.displayName()+" " + credentials;
     }
 
@@ -54,7 +50,7 @@
 
     public AuthorizationData parseBasicToken (AuthorizationData data)
             throws KustvaktException {
-        String[] credentials = transferEncoding.decodeBase64(data.getToken());
+        String[] credentials = TransferEncoding.decodeBase64(data.getToken());
         data.setUsername(credentials[0]);
         data.setPassword(credentials[1]);
         return data;
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/http/TransferEncoding.java b/full/src/main/java/de/ids_mannheim/korap/authentication/http/TransferEncoding.java
index c4120df..52d1a90 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/http/TransferEncoding.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/http/TransferEncoding.java
@@ -21,7 +21,7 @@
      * @param password password
      * @return
      */
-    public String encodeBase64 (String username, String password) {
+    public static String encodeBase64 (String username, String password) {
         String s = username + ":" + password;
         return new String(Base64.encodeBase64(s.getBytes()));
     }
@@ -32,7 +32,7 @@
      * @return username and password as an array of strings.
      * @throws KustvaktException 
      */
-    public String[] decodeBase64 (String encodedStr)
+    public static String[] decodeBase64 (String encodedStr)
             throws KustvaktException {
 
         ParameterChecker.checkStringValue(encodedStr, "encoded string");
diff --git a/full/src/main/java/de/ids_mannheim/korap/cache/ResourceCache.java b/full/src/main/java/de/ids_mannheim/korap/cache/ResourceCache.java
index 8e5871c..45f0ce7 100644
--- a/full/src/main/java/de/ids_mannheim/korap/cache/ResourceCache.java
+++ b/full/src/main/java/de/ids_mannheim/korap/cache/ResourceCache.java
@@ -1,22 +1,13 @@
 package de.ids_mannheim.korap.cache;
 
-import de.ids_mannheim.korap.config.KustvaktCacheable;
-import de.ids_mannheim.korap.exceptions.EmptyResultException;
-import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.exceptions.NotAuthorizedException;
-import de.ids_mannheim.korap.exceptions.StatusCodes;
-import de.ids_mannheim.korap.resources.KustvaktResource;
-import de.ids_mannheim.korap.resources.Permissions;
-import de.ids_mannheim.korap.resources.ResourceFactory;
-import de.ids_mannheim.korap.user.User;
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.Element;
-
-import java.util.Collection;
-
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import de.ids_mannheim.korap.config.KustvaktCacheable;
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+
 /**
  * @author hanl
  * @date 23/03/2014
diff --git a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
index 68b2ac6..b11f8cf 100644
--- a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
+++ b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
@@ -27,6 +27,7 @@
 import de.ids_mannheim.korap.constant.AuthenticationMethod;
 import de.ids_mannheim.korap.interfaces.EncryptionIface;
 import de.ids_mannheim.korap.oauth2.openid.OpenIdConfiguration;
+import de.ids_mannheim.korap.utils.TimeUtils;
 
 /**
  * Configuration for Kustvakt full version including properties
@@ -73,6 +74,10 @@
     private Set<String> clientCredentialsScopes;
     private int maxAuthenticationAttempts;
 
+    private int accessTokenExpiry;
+    private int refreshTokenExpiry;
+    private int authorizationCodeExpiry;
+
     private URL issuer;
     private URI issuerURI;
     private OpenIdConfiguration openidConfig;
@@ -218,7 +223,7 @@
                 "korap.ids-mannheim.de"));
 
         setMaxAuthenticationAttempts(Integer
-                .parseInt(properties.getProperty("oauth2.max.attempts", "3")));
+                .parseInt(properties.getProperty("oauth2.max.attempts", "1")));
 
         String scopes = properties.getProperty("oauth2.default.scopes",
                 "openid preferred_username");
@@ -230,6 +235,13 @@
                 .getProperty("oauth2.client.credentials.scopes", "client_info");
         setClientCredentialsScopes(Arrays.stream(clientScopes.split(" "))
                 .collect(Collectors.toSet()));
+
+        accessTokenExpiry = TimeUtils.convertTimeToSeconds(
+                properties.getProperty("oauth2.access.token.expiry", "1D"));
+        refreshTokenExpiry = TimeUtils.convertTimeToSeconds(
+                properties.getProperty("oauth2.refresh.token.expiry", "90D"));
+        authorizationCodeExpiry = TimeUtils.convertTimeToSeconds(properties
+                .getProperty("oauth2.authorization.code.expiry", "10M"));
     }
 
     private void setMailConfiguration (Properties properties) {
@@ -583,4 +595,28 @@
     public void setOpenidConfig (OpenIdConfiguration openidConfig) {
         this.openidConfig = openidConfig;
     }
+
+    public int getAccessTokenExpiry () {
+        return accessTokenExpiry;
+    }
+
+    public void setAccessTokenExpiry (int accessTokenExpiry) {
+        this.accessTokenExpiry = accessTokenExpiry;
+    }
+
+    public int getRefreshTokenExpiry () {
+        return refreshTokenExpiry;
+    }
+
+    public void setRefreshTokenExpiry (int refreshTokenExpiry) {
+        this.refreshTokenExpiry = refreshTokenExpiry;
+    }
+
+    public int getAuthorizationCodeExpiry () {
+        return authorizationCodeExpiry;
+    }
+
+    public void setAuthorizationCodeExpiry (int authorizationCodeExpiry) {
+        this.authorizationCodeExpiry = authorizationCodeExpiry;
+    }
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/handlers/ResourceDao.java b/full/src/main/java/de/ids_mannheim/korap/handlers/ResourceDao.java
deleted file mode 100644
index 9cf7165..0000000
--- a/full/src/main/java/de/ids_mannheim/korap/handlers/ResourceDao.java
+++ /dev/null
@@ -1,259 +0,0 @@
-package de.ids_mannheim.korap.handlers;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.springframework.dao.DataAccessException;
-import org.springframework.dao.IncorrectResultSizeDataAccessException;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-
-import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.exceptions.StatusCodes;
-import de.ids_mannheim.korap.exceptions.DatabaseException;
-import de.ids_mannheim.korap.interfaces.db.PersistenceClient;
-import de.ids_mannheim.korap.interfaces.db.ResourceOperationIface;
-import de.ids_mannheim.korap.resources.KustvaktResource;
-import de.ids_mannheim.korap.resources.ResourceFactory;
-import de.ids_mannheim.korap.user.User;
-import de.ids_mannheim.korap.utils.SqlBuilder;
-
-/**
- * Created by hanl on 7/21/14.
- */
-//todo: auditing // testing
-public class ResourceDao<T extends KustvaktResource>
-        implements ResourceOperationIface<T> {
-
-    private static Logger log = LogManager.getLogger(ResourceDao.class);
-    protected final NamedParameterJdbcTemplate jdbcTemplate;
-
-
-    public ResourceDao (PersistenceClient client) {
-        this.jdbcTemplate = (NamedParameterJdbcTemplate) client.getSource();
-    }
-
-
-    @Override
-    public Class<T> type () {
-        return (Class<T>) KustvaktResource.class;
-    }
-
-
-    // todo: testing
-    @Override
-    public List<T> getResources (Collection<Object> ids, User user)
-            throws KustvaktException {
-        String sql = "SELECT rs.*, rt.name_path FROM resource_store as rs inner join resource_tree as rt"
-                + " on rs.id=rt.child_id WHERE rs.id IN (:ids);";
-        MapSqlParameterSource parameters = new MapSqlParameterSource();
-        parameters.addValue("ids", ids);
-        try {
-            return (List<T>) this.jdbcTemplate.query(sql, parameters,
-                    new RowMapperFactory.ResourceMapper());
-        }
-        catch (DataAccessException e) {
-            log.error(
-                    "Exception during database retrieval for ids '" + ids + "'",
-                    e);
-            throw new DatabaseException(user.getId(), "resource_store",
-                    StatusCodes.DB_GET_FAILED,
-                    "Exception during database retrieval for ids '" + ids,
-                    ids.toString());
-        }
-
-    }
-
-
-    @Override
-    public int updateResource (T resource, User user) throws KustvaktException {
-        MapSqlParameterSource source = new MapSqlParameterSource();
-        source.addValue("id", resource.getPersistentID());
-        source.addValue("name", resource.getName());
-        source.addValue("desc", resource.getDescription());
-        source.addValue("data", resource.getStringData());
-        final String sql = "UPDATE resource_store set name=:name, data=:data, description=:desc where persistent_id=:id;";
-        try {
-            return this.jdbcTemplate.update(sql, source);
-        }
-        catch (DataAccessException e) {
-            log.error("Exception during database update for id '"
-                    + resource.getPersistentID() + "'", e);
-            throw new DatabaseException(user.getId(), "resource_store",
-                    StatusCodes.DB_UPDATE_FAILED, "Exception during database update for id '"
-                            + resource.getPersistentID(), resource.toString());
-        }
-    }
-
-
-    @Override
-    public int[] updateResources (List<T> resources, User user)
-            throws KustvaktException {
-        return new int[1];
-    }
-
-
-    @Override
-    public <T extends KustvaktResource> T findbyId (String id, User user)
-            throws KustvaktException {
-        MapSqlParameterSource source = new MapSqlParameterSource();
-        source.addValue("pid", id);
-        String sql = "SELECT rs.*, rt.name_path FROM resource_store as rs inner join resource_tree as rt"
-                + " on rs.id=rt.child_id WHERE rs.persistent_id=:pid";
-        //group by rs.id;";
-        try {
-            return (T) this.jdbcTemplate.queryForObject(sql, source,
-                    new RowMapperFactory.ResourceMapper());
-        }
-        catch (DataAccessException e) {
-            // empty results
-            return null;
-        }
-    }
-
-
-    public KustvaktResource findbyPath (String path, User user)
-            throws KustvaktException {
-        MapSqlParameterSource source = new MapSqlParameterSource();
-        source.addValue("path", path);
-        String sql = "SELECT rs.*, rt.name_path FROM resource_store as rs inner join resource_tree as rt on rs.id=rt.child_id WHERE rt.name_path=:path;";
-        try {
-            return this.jdbcTemplate.queryForObject(sql, source,
-                    new RowMapperFactory.ResourceMapper());
-        }
-        catch (DataAccessException e) {
-            if (e instanceof IncorrectResultSizeDataAccessException)
-                throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT,
-                        "invalid request path given!", path);
-            return null;
-        }
-    }
-
-
-    @Override
-    public <T extends KustvaktResource> T findbyId (Integer id, User user)
-            throws KustvaktException {
-        MapSqlParameterSource source = new MapSqlParameterSource();
-        source.addValue("id", id);
-        String sql = "SELECT rs.*, rt.name_path FROM resource_store as rs inner join resource_tree as rt on rs.id=rt.child_id "
-                + "WHERE rs.id=:id group by rs.id order by rt.depth desc;";
-        try {
-            return (T) this.jdbcTemplate.queryForObject(sql, source,
-                    new RowMapperFactory.ResourceMapper());
-        }
-        catch (DataAccessException e) {
-            if (e instanceof IncorrectResultSizeDataAccessException)
-                throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT,
-                        "invalid request id given!", String.valueOf(id));
-            return null;
-        }
-    }
-
-
-    @Override
-    public <T1 extends KustvaktResource> List<T1> findbyPartialId (String id,
-            User user) throws KustvaktException {
-        return null;
-    }
-
-
-    @Override
-    public int storeResource (T resource, User user) throws KustvaktException {
-        MapSqlParameterSource source = new MapSqlParameterSource();
-        KeyHolder holder = new GeneratedKeyHolder();
-        // parent_id necessary so trigger can be used for tree insert!
-        final String sql, parid;
-        SqlBuilder b = new SqlBuilder("resource_store");
-        b.insert(Attributes.NAME, Attributes.PARENT_ID,
-                Attributes.PERSISTENT_ID, Attributes.DESCRIPTION,
-                Attributes.CREATOR, Attributes.TYPE, Attributes.CREATED);
-        b.params(
-                ":name, :parent, :pid, :desc, :ow, :type, :created, :dtype, :data");
-
-        if (resource.getParentID() == null) {
-            sql = "INSERT INTO resource_store (name, parent_id, persistent_id, description, creator, type, created, data) "
-                    + "VALUES (:name, :parent, :pid, :desc, :ow, :type, :created, :data);";
-            parid = null;
-        }
-        else {
-            // fixme: use trigger for consistency check!
-            sql = "INSERT INTO resource_store (name, parent_id, persistent_id, description, creator, type, created, data) "
-                    + "select :name, id, :pid, :desc, :ow, :type, :created, :data from resource_store where persistent_id=:parent;";
-            parid = resource.getParentID();
-        }
-
-        source.addValue("name", resource.getName());
-        source.addValue("pid", resource.getPersistentID());
-        source.addValue("parent", parid);
-        source.addValue("ow", user.getId());
-        source.addValue("desc", resource.getDescription());
-        source.addValue("type",
-                ResourceFactory.getResourceMapping(resource.getClass()));
-        source.addValue("created", System.currentTimeMillis());
-        source.addValue("data", resource.getStringData());
-
-        try {
-            this.jdbcTemplate.update(sql, source, holder,
-                    new String[] { "id" });
-        }
-        catch (DataAccessException e) {
-            log.error("Exception during database store for id '"
-                    + resource.getPersistentID() + "'", e);
-            throw new DatabaseException(user.getId(), "resource_store",
-                    StatusCodes.DB_INSERT_FAILED,
-                    "Exception during database store for id '"
-                            + resource.getPersistentID(),
-                    resource.toString());
-        }
-        resource.setId(holder.getKey().intValue());
-        return resource.getId();
-    }
-
-
-    @Override
-    public int deleteResource (String id, User user) throws KustvaktException {
-        MapSqlParameterSource source = new MapSqlParameterSource();
-        source.addValue("id", id);
-        final String sql = "DELETE FROM resource_store WHERE persistent_id=:id;";
-        try {
-            return this.jdbcTemplate.update(sql, source);
-        }
-        catch (DataAccessException e) {
-            throw new DatabaseException(user.getId(), "resource_store",
-                    StatusCodes.DB_DELETE_FAILED, "Operation DELETE failed.",
-                    id);
-        }
-    }
-
-
-    @Override
-    public int size () {
-        final String sql = "SELECT COUNT(*) FROM resource_store;";
-        try {
-            return this.jdbcTemplate.queryForObject(sql,
-                    new HashMap<String, Object>(), Integer.class);
-        }
-        catch (DataAccessException e) {
-            return 0;
-        }
-    }
-
-
-    @Override
-    public int truncate () {
-        final String sql = "DELETE FROM resource_store;";
-        try {
-            return this.jdbcTemplate.update(sql, new HashMap<String, Object>());
-        }
-        catch (DataAccessException e) {
-            return -1;
-        }
-    }
-
-}
diff --git a/full/src/main/java/de/ids_mannheim/korap/handlers/RowMapperFactory.java b/full/src/main/java/de/ids_mannheim/korap/handlers/RowMapperFactory.java
index 39b7efa..2b52228 100644
--- a/full/src/main/java/de/ids_mannheim/korap/handlers/RowMapperFactory.java
+++ b/full/src/main/java/de/ids_mannheim/korap/handlers/RowMapperFactory.java
@@ -1,30 +1,28 @@
 package de.ids_mannheim.korap.handlers;
 
-import de.ids_mannheim.korap.auditing.AuditRecord;
-import de.ids_mannheim.korap.config.URIParam;
-import de.ids_mannheim.korap.resources.KustvaktResource;
-import de.ids_mannheim.korap.resources.ResourceFactory;
-import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.user.KorAPUser;
-import de.ids_mannheim.korap.user.ShibbolethUser;
-import de.ids_mannheim.korap.user.User;
-import org.springframework.jdbc.core.RowMapper;
-
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Timestamp;
 import java.util.Map;
 
+import org.springframework.jdbc.core.RowMapper;
+
+import de.ids_mannheim.korap.auditing.AuditRecord;
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.URIParam;
+import de.ids_mannheim.korap.user.KorAPUser;
+import de.ids_mannheim.korap.user.User;
+
 /**
  * @author hanl
  * @date 14/01/2014
  */
 public class RowMapperFactory {
 
-    public static class UserMapMapper implements RowMapper<Map> {
+    public static class UserMapMapper implements RowMapper<Map<?,?>> {
 
         @Override
-        public Map mapRow (ResultSet rs, int rowNum) throws SQLException {
+        public Map<?, ?> mapRow (ResultSet rs, int rowNum) throws SQLException {
             User user = new UserMapper().mapRow(rs, rowNum);
             return user.toMap();
         }
@@ -98,24 +96,4 @@
         }
     }
 
-    public static class ResourceMapper implements RowMapper<KustvaktResource> {
-
-        @Override
-        public KustvaktResource mapRow (ResultSet rs, int rowNum)
-                throws SQLException {
-            KustvaktResource r = ResourceFactory.getResource(rs.getInt("type"));
-            if (r != null) {
-                r.setId(rs.getInt("id"));
-                r.setName(rs.getString("name"));
-
-                r.setFields(rs.getString("data"));
-                r.setDescription(rs.getString("description"));
-                r.setCreated(rs.getLong("created"));
-                r.setPath(rs.getString("name_path"));
-                r.setPersistentID(rs.getString("persistent_id"));
-            }
-            return r;
-        }
-
-    }
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessTokenDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessTokenDao.java
index f7ee4ff..76daaab 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessTokenDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessTokenDao.java
@@ -14,6 +14,7 @@
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
+import de.ids_mannheim.korap.config.KustvaktCacheable;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.entity.AccessScope;
@@ -24,18 +25,23 @@
 
 @Repository
 @Transactional
-public class AccessTokenDao {
+public class AccessTokenDao extends KustvaktCacheable {
+
+    public AccessTokenDao () {
+        super("access_token", "key:access_token");
+    }
 
     @PersistenceContext
     private EntityManager entityManager;
 
+    @Deprecated
     public void storeAccessToken (Authorization authorization, String token)
             throws KustvaktException {
         ParameterChecker.checkObjectValue(authorization, "Authorization");
         ParameterChecker.checkStringValue(token, "accessToken");
 
         AccessToken accessToken = new AccessToken();
-        accessToken.setAuthorization(authorization);
+        // accessToken.setAuthorization(authorization);
         accessToken.setUserId(authorization.getUserId());
         accessToken.setToken(token);
         accessToken.setScopes(authorization.getScopes());
@@ -45,7 +51,7 @@
     }
 
     public void storeAccessToken (String token, Set<AccessScope> scopes,
-            String userId, ZonedDateTime authenticationTime)
+            String userId, String clientId, ZonedDateTime authenticationTime)
             throws KustvaktException {
         ParameterChecker.checkObjectValue(scopes, "scopes");
         ParameterChecker.checkObjectValue(authenticationTime,
@@ -54,6 +60,7 @@
         accessToken.setToken(token);
         accessToken.setScopes(scopes);
         accessToken.setUserId(userId);
+        accessToken.setClientId(clientId);
         accessToken.setUserAuthenticationTime(authenticationTime);
         entityManager.persist(accessToken);
     }
@@ -61,6 +68,12 @@
 
     public AccessToken retrieveAccessToken (String accessToken)
             throws KustvaktException {
+
+        AccessToken token = (AccessToken) this.getCacheValue(accessToken);
+        if (token != null) {
+            return token;
+        }
+
         CriteriaBuilder builder = entityManager.getCriteriaBuilder();
         CriteriaQuery<AccessToken> query =
                 builder.createQuery(AccessToken.class);
@@ -69,7 +82,9 @@
         query.where(builder.equal(root.get(AccessToken_.token), accessToken));
         Query q = entityManager.createQuery(query);
         try {
-            return (AccessToken) q.getSingleResult();
+            token = (AccessToken) q.getSingleResult();
+            this.storeInCache(accessToken, token);
+            return token;
         }
         catch (NoResultException e) {
             throw new KustvaktException(StatusCodes.INVALID_ACCESS_TOKEN,
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationCacheDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationCacheDao.java
new file mode 100644
index 0000000..eed72d4
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationCacheDao.java
@@ -0,0 +1,72 @@
+package de.ids_mannheim.korap.oauth2.dao;
+
+import java.time.ZonedDateTime;
+import java.util.Set;
+
+import de.ids_mannheim.korap.config.KustvaktCacheable;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
+import de.ids_mannheim.korap.oauth2.entity.AccessScope;
+import de.ids_mannheim.korap.oauth2.entity.Authorization;
+import de.ids_mannheim.korap.oauth2.interfaces.AuthorizationDaoInterface;
+import de.ids_mannheim.korap.utils.ParameterChecker;
+
+public class AuthorizationCacheDao extends KustvaktCacheable
+        implements AuthorizationDaoInterface {
+
+    public AuthorizationCacheDao () {
+        super("authorization", "key:authorization");
+    }
+
+    @Override
+    public Authorization storeAuthorizationCode (String clientId, String userId,
+            String code, Set<AccessScope> scopes, String redirectURI,
+            ZonedDateTime authenticationTime, String nonce)
+            throws KustvaktException {
+        ParameterChecker.checkStringValue(clientId, "client_id");
+        ParameterChecker.checkStringValue(userId, "userId");
+        ParameterChecker.checkStringValue(code, "authorization code");
+        ParameterChecker.checkCollection(scopes, "scopes");
+        ParameterChecker.checkObjectValue(authenticationTime,
+                "user authentication time");
+
+        Authorization authorization = new Authorization();
+        authorization.setCode(code);
+        authorization.setClientId(clientId);
+        authorization.setUserId(userId);
+        authorization.setScopes(scopes);
+        authorization.setRedirectURI(redirectURI);
+        authorization.setUserAuthenticationTime(authenticationTime);
+        authorization.setNonce(nonce);
+        authorization.setCreatedDate(ZonedDateTime.now());
+
+        this.storeInCache(code, authorization);
+        return authorization;
+    }
+
+    @Override
+    public Authorization retrieveAuthorizationCode (String code)
+            throws KustvaktException {
+
+        Object auth = this.getCacheValue(code);
+        if (auth != null) {
+            return (Authorization) auth;
+        }
+        else {
+            throw new KustvaktException(StatusCodes.INVALID_AUTHORIZATION,
+                    "Authorization is invalid.", OAuth2Error.INVALID_REQUEST);
+        }
+    }
+
+    @Override
+    public Authorization updateAuthorization (Authorization authorization)
+            throws KustvaktException {
+
+        this.storeInCache(authorization.getCode(), authorization);
+        Authorization auth =
+                (Authorization) this.getCacheValue(authorization.getCode());
+        return auth;
+    }
+
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationDao.java
index 82557c0..c62b130 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AuthorizationDao.java
@@ -20,11 +20,12 @@
 import de.ids_mannheim.korap.oauth2.entity.AccessScope;
 import de.ids_mannheim.korap.oauth2.entity.Authorization;
 import de.ids_mannheim.korap.oauth2.entity.Authorization_;
+import de.ids_mannheim.korap.oauth2.interfaces.AuthorizationDaoInterface;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 
 @Transactional
 @Repository
-public class AuthorizationDao {
+public class AuthorizationDao implements AuthorizationDaoInterface{
 
     @PersistenceContext
     private EntityManager entityManager;
@@ -39,18 +40,18 @@
         ParameterChecker.checkObjectValue(authenticationTime,
                 "user authentication time");
 
-        Authorization authCode = new Authorization();
-        authCode.setCode(code);
-        authCode.setClientId(clientId);
-        authCode.setUserId(userId);
-        authCode.setScopes(scopes);
-        authCode.setRedirectURI(redirectURI);
-        authCode.setUserAuthenticationTime(authenticationTime);
-        authCode.setNonce(nonce);
+        Authorization authorization = new Authorization();
+        authorization.setCode(code);
+        authorization.setClientId(clientId);
+        authorization.setUserId(userId);
+        authorization.setScopes(scopes);
+        authorization.setRedirectURI(redirectURI);
+        authorization.setUserAuthenticationTime(authenticationTime);
+        authorization.setNonce(nonce);
 
-        entityManager.persist(authCode);
+        entityManager.persist(authorization);
         // what if unique fails
-        return authCode;
+        return authorization;
     }
 
     public Authorization retrieveAuthorizationCode (String code)
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessScope.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessScope.java
index 46d2b5c..f7951d9 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessScope.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessScope.java
@@ -1,5 +1,6 @@
 package de.ids_mannheim.korap.oauth2.entity;
 
+import java.io.Serializable;
 import java.util.List;
 
 import javax.persistence.Entity;
@@ -15,7 +16,9 @@
 @Setter
 @Entity
 @Table(name = "oauth2_access_scope")
-public class AccessScope {
+public class AccessScope implements Serializable{
+
+    private static final long serialVersionUID = -7356877266702636705L;
 
     @Id
     private String id;
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessToken.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessToken.java
index 55d0950..ce7cfd8 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessToken.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessToken.java
@@ -1,5 +1,6 @@
 package de.ids_mannheim.korap.oauth2.entity;
 
+import java.io.Serializable;
 import java.time.ZonedDateTime;
 import java.util.Set;
 
@@ -12,7 +13,6 @@
 import javax.persistence.JoinColumn;
 import javax.persistence.JoinTable;
 import javax.persistence.ManyToMany;
-import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
 
@@ -23,7 +23,9 @@
 @Setter
 @Entity
 @Table(name = "oauth2_access_token")
-public class AccessToken {
+public class AccessToken implements Serializable{
+
+    private static final long serialVersionUID = 8452701765986475302L;
 
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -33,16 +35,16 @@
     private ZonedDateTime createdDate;
     @Column(name = "user_id")
     private String userId;
+    @Column(name = "client_id")
+    private String clientId;
     @Column(name = "is_revoked")
     private boolean isRevoked;
-    @Column(name = "total_attempts")
-    private int totalAttempts;
     @Column(name = "user_auth_time", updatable = false)
     private ZonedDateTime userAuthenticationTime;
     
-    @OneToOne(fetch=FetchType.LAZY)
-    @JoinColumn(name="authorization_id")
-    private Authorization authorization;
+//    @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.REMOVE)
+//    @JoinColumn(name="authorization_id")
+//    private Authorization authorization;
     
     @ManyToMany(fetch = FetchType.EAGER)
     @JoinTable(name = "oauth2_access_token_scope",
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/interfaces/AuthorizationDaoInterface.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/interfaces/AuthorizationDaoInterface.java
new file mode 100644
index 0000000..f9c7280
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/interfaces/AuthorizationDaoInterface.java
@@ -0,0 +1,21 @@
+package de.ids_mannheim.korap.oauth2.interfaces;
+
+import java.time.ZonedDateTime;
+import java.util.Set;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.entity.AccessScope;
+import de.ids_mannheim.korap.oauth2.entity.Authorization;
+
+public interface AuthorizationDaoInterface {
+
+    public Authorization storeAuthorizationCode (String clientId, String userId,
+            String code, Set<AccessScope> scopes, String redirectURI,
+            ZonedDateTime authenticationTime, String nonce) throws KustvaktException;
+    
+    public Authorization retrieveAuthorizationCode (String code)
+            throws KustvaktException;
+    
+    public Authorization updateAuthorization (Authorization authorization)
+            throws KustvaktException;
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
index ec97923..7f61478 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
@@ -1,5 +1,6 @@
 package de.ids_mannheim.korap.oauth2.oltu.service;
 
+import java.time.ZoneId;
 import java.time.ZonedDateTime;
 import java.util.Set;
 
@@ -15,6 +16,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
@@ -58,7 +60,8 @@
             Set<String> scopes =
                     scopeService.filterScopes(oAuthRequest.getScopes(),
                             config.getClientCredentialsScopes());
-            return createsAccessTokenResponse(scopes, null, authenticationTime);
+            return createsAccessTokenResponse(scopes,
+                    oAuthRequest.getClientId(), null, authenticationTime);
         }
         else {
             throw new KustvaktException(StatusCodes.UNSUPPORTED_GRANT_TYPE,
@@ -88,9 +91,49 @@
         ZonedDateTime authenticationTime = authenticateUser(
                 oAuthRequest.getUsername(), oAuthRequest.getPassword(), scopes);
 
-        return createsAccessTokenResponse(scopes, oAuthRequest.getUsername(),
-                authenticationTime);
+        return createsAccessTokenResponse(scopes, oAuthRequest.getClientId(),
+                oAuthRequest.getUsername(), authenticationTime);
+    }
 
+    /**
+     * Clients must authenticate.
+     * Client credentials grant is limited to native clients.
+     * 
+     * @param clientId
+     *            client_id parameter, required
+     * @param clientSecret
+     *            client_secret parameter, required
+     * @param scopes
+     * @return
+     * @return authentication time
+     * @throws KustvaktException
+     * @throws OAuthSystemException
+     */
+    protected ZonedDateTime requestAccessTokenWithClientCredentials (
+            String clientId, String clientSecret, Set<String> scopes)
+            throws KustvaktException {
+
+        if (clientSecret == null || clientSecret.isEmpty()) {
+            throw new KustvaktException(
+                    StatusCodes.CLIENT_AUTHENTICATION_FAILED,
+                    "Missing parameters: client_secret",
+                    OAuth2Error.INVALID_REQUEST);
+        }
+
+        // OAuth2Client client =
+        clientService.authenticateClient(clientId, clientSecret);
+
+        // if (!client.isNative()) {
+        // throw new KustvaktException(
+        // StatusCodes.CLIENT_AUTHENTICATION_FAILED,
+        // "Client credentials grant is not allowed for third party
+        // clients",
+        // OAuth2Error.UNAUTHORIZED_CLIENT);
+        // }
+
+        ZonedDateTime authenticationTime =
+                ZonedDateTime.now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE));
+        return authenticationTime;
     }
 
     /**
@@ -104,7 +147,7 @@
      * @throws KustvaktException
      */
     private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
-            String userId, ZonedDateTime authenticationTime)
+            String clientId, String userId, ZonedDateTime authenticationTime)
             throws OAuthSystemException, KustvaktException {
 
         String accessToken = oauthIssuer.accessToken();
@@ -112,7 +155,7 @@
 
         Set<AccessScope> accessScopes =
                 scopeService.convertToAccessScope(scopes);
-        tokenDao.storeAccessToken(accessToken, accessScopes, userId,
+        tokenDao.storeAccessToken(accessToken, accessScopes, userId, clientId,
                 authenticationTime);
 
         return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
@@ -129,7 +172,9 @@
         String accessToken = oauthIssuer.accessToken();
         // String refreshToken = oauthIssuer.refreshToken();
 
-        tokenDao.storeAccessToken(authorization, accessToken);
+        tokenDao.storeAccessToken(accessToken, authorization.getScopes(),
+                authorization.getUserId(), authorization.getClientId(),
+                authorization.getUserAuthenticationTime());
 
         String scopes = scopeService
                 .convertAccessScopesToString(authorization.getScopes());
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java
index db118f5..341ff97 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java
@@ -107,8 +107,13 @@
             checkResponseType(responseType.toString());
 
             Scope scope = authzRequest.getScope();
-            Set<String> scopeSet = (scope != null)
-                    ? new HashSet<>(scope.toStringList()) : null;
+            Set<String> scopeSet = null;
+            if (scope != null) {
+                scopeSet = new HashSet<>(scope.toStringList());
+            }
+            else {
+                scopeSet = config.getDefaultAccessScopes();
+            }
             createAuthorization(username, clientId, redirectUriStr, scopeSet,
                     code.getValue(), authenticationTime, nonce);
         }
@@ -184,15 +189,16 @@
         if (nonce != null && !nonce.getValue().isEmpty()) {
             nonceValue = nonce.getValue();
         }
-        
+
         checkMaxAge(authRequest.getMaxAge(), authenticationTime);
 
         AuthorizationRequest request = authRequest;
         return handleAuthorizationRequest(request, code, username,
                 authenticationTime, nonceValue);
     }
-    
-    private void checkMaxAge (int maxAge, ZonedDateTime authenticationTime) throws KustvaktException {
+
+    private void checkMaxAge (int maxAge, ZonedDateTime authenticationTime)
+            throws KustvaktException {
         if (maxAge > 0) {
             ZonedDateTime now =
                     ZonedDateTime.now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE));
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java
index a61cbe1..91a51bf 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java
@@ -8,6 +8,7 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import com.nimbusds.jose.JOSEException;
@@ -45,6 +46,7 @@
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
+import de.ids_mannheim.korap.oauth2.dao.AccessTokenDao;
 import de.ids_mannheim.korap.oauth2.entity.AccessScope;
 import de.ids_mannheim.korap.oauth2.entity.Authorization;
 import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
@@ -69,6 +71,9 @@
 @Service
 public class OpenIdTokenService extends OAuth2TokenService {
 
+    @Autowired
+    private AccessTokenDao tokenDao;
+
     public AccessTokenResponse requestAccessToken (TokenRequest tokenRequest)
             throws KustvaktException {
         AuthorizationGrant grant = tokenRequest.getAuthorizationGrant();
@@ -128,10 +133,14 @@
             ClientAuthentication clientAuthentication, ClientID clientId)
             throws KustvaktException {
 
-        Set<String> scopes = null;
+        Set<String> scopeSet = null;
         if (scope != null) {
-            scopes = new HashSet<String>();
-            scopes.addAll(scope.toStringList());
+            scopeSet = new HashSet<String>();
+            scopeSet.addAll(scope.toStringList());
+        }
+        else {
+            scopeSet = config.getDefaultAccessScopes();
+            scope = new Scope(scopeSet.toArray(new String[scopeSet.size()]));
         }
 
         ZonedDateTime authenticationTime;
@@ -145,8 +154,7 @@
             }
             else {
                 clientIdStr = clientId.getValue();
-                client = clientService.authenticateClient(clientIdStr,
-                        null);
+                client = clientService.authenticateClient(clientIdStr, null);
             }
         }
         else {
@@ -156,19 +164,24 @@
             client = clientService.authenticateClient(clientCredentials[0],
                     clientCredentials[1]);
         }
-        
+
         if (!client.isNative()) {
-            throw new KustvaktException(
-                    StatusCodes.CLIENT_AUTHORIZATION_FAILED,
+            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
                     "Password grant is not allowed for third party clients",
                     OAuth2Error.UNAUTHORIZED_CLIENT);
         }
-        
-        authenticationTime =
-                authenticateUser(username, password, scopes);
-        
-        return createsAccessTokenResponse(scope, clientIdStr, username,
-                authenticationTime, null);
+
+        authenticationTime = authenticateUser(username, password, scopeSet);
+
+        AccessToken accessToken =
+                new BearerAccessToken(config.getTokenTTL(), scope);
+
+        tokenDao.storeAccessToken(accessToken.getValue(),
+                scopeService.convertToAccessScope(scopeSet), username,
+                clientIdStr, authenticationTime);
+
+        return createsAccessTokenResponse(accessToken, scope, clientIdStr,
+                username, authenticationTime, null);
     }
 
     private AccessTokenResponse requestAccessTokenWithAuthorizationCode (
@@ -211,22 +224,26 @@
         String[] scopeArray = scopes.stream().map(scope -> scope.toString())
                 .toArray(String[]::new);
         Scope scope = new Scope(scopeArray);
-        return createsAccessTokenResponse(scope, authorization.getClientId(),
-                authorization.getUserId(),
+        AccessToken accessToken =
+                new BearerAccessToken(config.getTokenTTL(), scope);
+        tokenDao.storeAccessToken(accessToken.getValue(), scopes,
+                authorization.getUserId(), authorization.getClientId(),
+                authorization.getUserAuthenticationTime());
+
+        return createsAccessTokenResponse(accessToken, scope,
+                authorization.getClientId(), authorization.getUserId(),
                 authorization.getUserAuthenticationTime(),
                 authorization.getNonce());
     }
 
-    private AccessTokenResponse createsAccessTokenResponse (Scope scope,
-            String clientId, String userId,
-            ZonedDateTime userAuthenticationTime, String nonce)
+    private AccessTokenResponse createsAccessTokenResponse (
+            AccessToken accessToken, Scope scope, String clientId,
+            String userId, ZonedDateTime userAuthenticationTime, String nonce)
             throws KustvaktException {
 
-        AccessToken accessToken =
-                new BearerAccessToken(config.getTokenTTL(), scope);
         RefreshToken refreshToken = new RefreshToken();
 
-        if (scope != null && scope.contains("openid")) {
+        if (scope.contains("openid")) {
             JWTClaimsSet claims = createIdTokenClaims(clientId, userId,
                     userAuthenticationTime, nonce);
             SignedJWT idToken = signIdToken(claims,
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
index f70ce8e..ae29e4c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
@@ -12,10 +12,10 @@
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
-import de.ids_mannheim.korap.oauth2.dao.AuthorizationDao;
 import de.ids_mannheim.korap.oauth2.entity.AccessScope;
 import de.ids_mannheim.korap.oauth2.entity.Authorization;
 import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
+import de.ids_mannheim.korap.oauth2.interfaces.AuthorizationDaoInterface;
 
 @Service(value = "authorizationService")
 public class OAuth2AuthorizationService {
@@ -27,12 +27,11 @@
     protected OAuth2ClientService clientService;
     @Autowired
     protected OAuth2ScopeService scopeService;
+    @Autowired
+    private AuthorizationDaoInterface authorizationDao;
 
     @Autowired
-    private AuthorizationDao authorizationDao;
-
-    @Autowired
-    private FullConfiguration config;
+    protected FullConfiguration config;
 
     /**
      * Authorization code request does not require client
@@ -178,7 +177,8 @@
 
     private boolean isExpired (ZonedDateTime createdDate) {
         jlog.debug("createdDate: " + createdDate);
-        ZonedDateTime expiration = createdDate.plusSeconds(60);
+        ZonedDateTime expiration =
+                createdDate.plusSeconds(config.getAuthorizationCodeExpiry());
         ZonedDateTime now = ZonedDateTime.now();
         jlog.debug("expiration: " + expiration + ", now: " + now);
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
index cd4eec1..6f1ce49 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
@@ -1,5 +1,6 @@
 package de.ids_mannheim.korap.oauth2.service;
 
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -37,7 +38,7 @@
      * @return
      * @throws KustvaktException
      */
-    public Set<AccessScope> convertToAccessScope (Set<String> scopes)
+    public Set<AccessScope> convertToAccessScope (Collection<String> scopes)
             throws KustvaktException {
 
         List<AccessScope> definedScopes = accessScopeDao.retrieveAccessScopes();
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
index d6c11d9..d95cb65 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
@@ -132,45 +132,4 @@
         return authenticationTime;
     }
 
-    /**
-     * Clients must authenticate.
-     * Client credentials grant is limited to native clients.
-     * 
-     * @param clientId
-     *            client_id parameter, required
-     * @param clientSecret
-     *            client_secret parameter, required
-     * @param scopes
-     * @return authentication time
-     * @throws KustvaktException
-     * @throws OAuthSystemException
-     */
-    protected ZonedDateTime requestAccessTokenWithClientCredentials (
-            String clientId, String clientSecret, Set<String> scopes)
-            throws KustvaktException {
-
-        if (clientSecret == null || clientSecret.isEmpty()) {
-            throw new KustvaktException(
-                    StatusCodes.CLIENT_AUTHENTICATION_FAILED,
-                    "Missing parameters: client_secret",
-                    OAuth2Error.INVALID_REQUEST);
-        }
-
-        // OAuth2Client client =
-        clientService.authenticateClient(clientId, clientSecret);
-
-        // if (!client.isNative()) {
-        // throw new KustvaktException(
-        // StatusCodes.CLIENT_AUTHENTICATION_FAILED,
-        // "Client credentials grant is not allowed for third party
-        // clients",
-        // OAuth2Error.UNAUTHORIZED_CLIENT);
-        // }
-        ZonedDateTime authenticationTime =
-                ZonedDateTime.now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE));
-        return authenticationTime;
-    }
-
-
-
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/filter/DemoFilter.java b/full/src/main/java/de/ids_mannheim/korap/web/filter/DemoFilter.java
index 321417d..b15f5e3 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/filter/DemoFilter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/filter/DemoFilter.java
@@ -3,8 +3,6 @@
 import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.ext.Provider;
 
-import org.springframework.beans.factory.annotation.Autowired;
-
 import com.sun.jersey.spi.container.ContainerRequest;
 import com.sun.jersey.spi.container.ContainerRequestFilter;
 import com.sun.jersey.spi.container.ContainerResponseFilter;
@@ -23,13 +21,10 @@
 @Provider
 public class DemoFilter implements ContainerRequestFilter, ResourceFilter {
 
-    @Autowired
-    private HttpAuthorizationHandler handler;
-    
     @Override
     public ContainerRequest filter (ContainerRequest request) {
-        String authentication = request
-                .getHeaderValue(ContainerRequest.AUTHORIZATION);
+        String authentication =
+                request.getHeaderValue(ContainerRequest.AUTHORIZATION);
         if (authentication == null || authentication.isEmpty()) {
             try {
                 request.getUserPrincipal();
@@ -46,7 +41,8 @@
         TokenContext context = new TokenContext();
         String token = null;
         try {
-            token = handler.createBasicAuthorizationHeaderValue("demo", "demo2015");
+            token = HttpAuthorizationHandler
+                    .createBasicAuthorizationHeaderValue("demo", "demo2015");
         }
         catch (KustvaktException e) {
             e.printStackTrace();
diff --git a/full/src/main/resources/db/new-mysql/V1.4__oauth2_tables.sql b/full/src/main/resources/db/new-mysql/V1.4__oauth2_tables.sql
index 234df42..b8df487 100644
--- a/full/src/main/resources/db/new-mysql/V1.4__oauth2_tables.sql
+++ b/full/src/main/resources/db/new-mysql/V1.4__oauth2_tables.sql
@@ -54,14 +54,13 @@
 CREATE TABLE IF NOT EXISTS oauth2_access_token (
 	id INTEGER PRIMARY KEY AUTO_INCREMENT,
 	token VARCHAR(255) NOT NULL,
-	authorization_id INTEGER DEFAULT NULL,
 	user_id VARCHAR(100) DEFAULT NULL,
+	client_id VARCHAR(100) DEFAULT NULL,
 	created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 	is_revoked BOOLEAN DEFAULT 0,
-	total_attempts INTEGER DEFAULT 0,
 	user_auth_time TIMESTAMP NULL,
-	FOREIGN KEY (authorization_id)
-	   REFERENCES oauth2_authorization(id)
+	FOREIGN KEY (client_id)
+	   REFERENCES oauth2_client(id)
 );
 
 CREATE TABLE oauth2_access_token_scope (
diff --git a/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql b/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
index f227752..2310c12 100644
--- a/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
+++ b/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
@@ -59,14 +59,13 @@
 CREATE TABLE IF NOT EXISTS oauth2_access_token (
 	id INTEGER PRIMARY KEY AUTOINCREMENT,
 	token VARCHAR(255) NOT NULL,
-	authorization_id INTEGER DEFAULT NULL,
 	user_id VARCHAR(100) DEFAULT NULL,
+	client_id VARCHAR(100) DEFAULT NULL,
 	created_date TIMESTAMP DEFAULT (datetime('now','localtime')),
 	is_revoked BOOLEAN DEFAULT 0,
-	total_attempts INTEGER DEFAULT 0,
 	user_auth_time TIMESTAMP NOT NULL,
-	FOREIGN KEY (authorization_id)
-	   REFERENCES oauth2_authorization(id)
+	FOREIGN KEY (client_id)
+	   REFERENCES oauth2_client(id)
 );
 
 CREATE TABLE oauth2_access_token_scope (
diff --git a/full/src/main/resources/default-config.xml b/full/src/main/resources/default-config.xml
index 456ecff..90ea568 100644
--- a/full/src/main/resources/default-config.xml
+++ b/full/src/main/resources/default-config.xml
@@ -159,6 +159,7 @@
 	<!-- Data access objects -->
 	<bean id="resourceDao" class="de.ids_mannheim.korap.dao.ResourceDao" />
 	<bean id="accessScopeDao" class="de.ids_mannheim.korap.oauth2.dao.AccessScopeDao" />
+	<bean id="authorizationDao" class="de.ids_mannheim.korap.oauth2.dao.AuthorizationCacheDao" />
 
 	<!-- props are injected from default-config.xml -->
 	<bean id="kustvakt_config" class="de.ids_mannheim.korap.config.FullConfiguration">
@@ -215,10 +216,6 @@
 		<constructor-arg ref="kustvakt_db" />
 	</bean>
 
-	<bean id="resource_provider" class="de.ids_mannheim.korap.handlers.ResourceDao">
-		<constructor-arg ref="kustvakt_db" />
-	</bean>
-
 	<bean id="document_provider" class="de.ids_mannheim.korap.handlers.DocumentDao">
 		<constructor-arg ref="kustvakt_db" />
 	</bean>
@@ -284,7 +281,6 @@
 	<util:list id="kustvakt_resources"
 		value-type="de.ids_mannheim.korap.interfaces.db.ResourceOperationIface">
 		<ref bean="document_provider" />
-		<ref bean="resource_provider" />
 	</util:list>
 
 	<!-- specify type for constructor argument -->
diff --git a/full/src/main/resources/ehcache.xml b/full/src/main/resources/ehcache.xml
index 17cff24..be4e71e 100644
--- a/full/src/main/resources/ehcache.xml
+++ b/full/src/main/resources/ehcache.xml
@@ -3,38 +3,13 @@
     <defaultCache eternal='true' overflowToDisk='false'/>
     <!--maxBytesLocalHeap="200M"-->
     <diskStore path="./cache_store"/>
-
-    <cache name="documents"
-           timeToIdleSeconds="172800"
-           eternal='false'
-           memoryStoreEvictionPolicy="LRU"
-           maxEntriesLocalHeap="2000"
-           overflowToDisk='false'/>
-    <cache name='users'
-           timeToIdleSeconds="172800"
-           eternal='false'
-           memoryStoreEvictionPolicy="LRU"
-           maxEntriesLocalHeap="50"
-           overflowToDisk='false'/>
+    
     <cache name='id_tokens'
            eternal='true'
            maxElementsOnDisk="10000000"
            memoryStoreEvictionPolicy="LRU"
            maxEntriesLocalHeap="50"
            overflowToDisk='true'/>
-    <cache name='id_tokens_inv'
-           eternal='true'
-           maxElementsOnDisk="10000000"
-           memoryStoreEvictionPolicy="LRU"
-           maxEntriesLocalHeap="50"
-           overflowToDisk='true'/>
-
-    <cache name='auth_sessions'
-           timeToIdleSeconds="172800"
-           eternal='false'
-           memoryStoreEvictionPolicy="LRU"
-           maxEntriesLocalHeap="100"
-           overflowToDisk='false'/>
 
     <cache name='auth_codes'
            timeToIdleSeconds="600"
@@ -52,4 +27,21 @@
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            statistics="false"/>
+           
+           
+    <!-- EM --> 
+    <cache name='authorization'
+           timeToLiveSeconds="1000"
+           eternal='false'
+           memoryStoreEvictionPolicy="LRU"
+           maxEntriesLocalHeap="100"
+           overflowToDisk='false'/>
+           
+    <cache name='access_token'
+           timeToIdleSeconds="3600"
+           timeToLiveSeconds="15000"
+           eternal='false'
+           memoryStoreEvictionPolicy="LRU"
+           maxEntriesLocalHeap="500"
+           overflowToDisk='false'/>          
 </ehcache>
diff --git a/full/src/main/resources/kustvakt.conf b/full/src/main/resources/kustvakt.conf
index 654a1ab..0c21e43 100644
--- a/full/src/main/resources/kustvakt.conf
+++ b/full/src/main/resources/kustvakt.conf
@@ -48,7 +48,11 @@
 ### oauth.password.authentication values)
 oauth.password.authentication = TEST
 oauth2.native.client.host = korap.ids-mannheim.de
-oauth2.max.attempts = 3
+oauth2.max.attempts = 1
+# expiry in seconds (S), minutes (M), hours (H), days (D)
+oauth2.access.token.expiry = 1D
+oauth2.refresh.token.expiry = 90D
+oauth2.authorization.code.expiry = 10M
 # -- scopes separated by space
 oauth2.default.scopes = search match_info 
 oauth2.client.credentials.scopes = client_info
diff --git a/full/src/main/resources/kustvakt.info b/full/src/main/resources/kustvakt.info
index c1c6cea..4a0344a 100644
--- a/full/src/main/resources/kustvakt.info
+++ b/full/src/main/resources/kustvakt.info
@@ -4,5 +4,5 @@
 # use this file to define the properties and logging file names
 kustvakt.properties=./kustvakt.conf
 kustvakt.logging=./log4j.properties
-kustvakt.caching=true
+kustvakt.cache=true
 kustvakt.cache_store=./store
\ No newline at end of file