Changed OAuth2 token request using Nimbus (#650)

Change-Id: I838c03013878675613901f62b6a047a845dd09a3
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
deleted file mode 100644
index 2311240..0000000
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
+++ /dev/null
@@ -1,645 +0,0 @@
-package de.ids_mannheim.korap.oauth2.oltu.service;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import jakarta.persistence.NoResultException;
-
-import org.apache.oltu.oauth2.as.request.AbstractOAuthTokenRequest;
-import org.apache.oltu.oauth2.as.response.OAuthASResponse;
-import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
-import org.apache.oltu.oauth2.common.message.OAuthResponse;
-import org.apache.oltu.oauth2.common.message.types.GrantType;
-import org.apache.oltu.oauth2.common.message.types.TokenType;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import com.unboundid.ldap.sdk.LDAPException;
-
-import de.ids_mannheim.korap.authentication.LdapAuth3;
-import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.constant.AuthenticationMethod;
-import de.ids_mannheim.korap.encryption.RandomCodeGenerator;
-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.dao.RefreshTokenDao;
-import de.ids_mannheim.korap.oauth2.dto.OAuth2TokenDto;
-import de.ids_mannheim.korap.oauth2.entity.AccessScope;
-import de.ids_mannheim.korap.oauth2.entity.AccessToken;
-import de.ids_mannheim.korap.oauth2.entity.Authorization;
-import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
-import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
-import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeAllTokenSuperRequest;
-import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeTokenRequest;
-import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeTokenSuperRequest;
-import de.ids_mannheim.korap.oauth2.service.OAuth2ClientService;
-import de.ids_mannheim.korap.oauth2.service.OAuth2TokenService;
-import jakarta.ws.rs.core.Response.Status;
-
-/** Implementation of token service using Apache Oltu.
- * 
- * @author margaretha
- *
- */
-@Service
-public class OltuTokenService extends OAuth2TokenService {
-
-    @Autowired
-    private RandomCodeGenerator randomGenerator;
-
-    @Autowired
-    private AccessTokenDao tokenDao;
-    @Autowired
-    private RefreshTokenDao refreshDao;
-    
-    @Autowired
-    private OAuth2ClientService clientService;
-
-    public OAuthResponse requestAccessToken (
-            AbstractOAuthTokenRequest oAuthRequest)
-            throws KustvaktException, OAuthSystemException {
-
-        String grantType = oAuthRequest.getGrantType();
-
-        if (grantType.equals(GrantType.AUTHORIZATION_CODE.toString())) {
-            return requestAccessTokenWithAuthorizationCode(
-                    oAuthRequest.getCode(), oAuthRequest.getRedirectURI(),
-                    oAuthRequest.getClientId(), oAuthRequest.getClientSecret());
-        }
-        else if (grantType.equals(GrantType.PASSWORD.toString())) {
-            return requestAccessTokenWithPassword(oAuthRequest.getClientId(),
-                    oAuthRequest.getClientSecret(), oAuthRequest.getUsername(),
-                    oAuthRequest.getPassword(), oAuthRequest.getScopes());
-        }
-        else if (grantType.equals(GrantType.CLIENT_CREDENTIALS.toString())) {
-            return requestAccessTokenWithClientCredentials(
-                    oAuthRequest.getClientId(), oAuthRequest.getClientSecret(),
-                    oAuthRequest.getScopes());
-        }
-        else if (grantType.equals(GrantType.REFRESH_TOKEN.toString())) {
-            return requestAccessTokenWithRefreshToken(
-                    oAuthRequest.getRefreshToken(), oAuthRequest.getScopes(),
-                    oAuthRequest.getClientId(), oAuthRequest.getClientSecret());
-        }
-        else {
-            throw new KustvaktException(StatusCodes.UNSUPPORTED_GRANT_TYPE,
-                    grantType + " is not supported.",
-                    OAuth2Error.UNSUPPORTED_GRANT_TYPE);
-        }
-
-    }
-
-    private boolean isInternalClient (String clientIpAddress) {
-        try {
-            InetAddress ip = InetAddress.getByName(clientIpAddress);
-            if (ip.isSiteLocalAddress()) {
-                return true;
-            }
-        }
-        catch (UnknownHostException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-        return false;
-    }
-
-    /**
-     * Revokes all access token associated with the given refresh
-     * token, and creates a new access token and a new refresh
-     * token with the same scopes. Thus, at one point of time,
-     * there is only one active access token associated with
-     * a refresh token.
-     * 
-     * Client authentication is done using the given client
-     * credentials.
-     * 
-     * TODO: should create a new refresh token when the old refresh
-     * token is used (DONE)
-     * 
-     * @param refreshTokenStr
-     * @param requestScopes
-     * @param clientId
-     * @param clientSecret
-     * @return if successful, a new access token
-     * @throws KustvaktException
-     * @throws OAuthSystemException
-     */
-    private OAuthResponse requestAccessTokenWithRefreshToken (
-            String refreshTokenStr, Set<String> requestScopes, String clientId,
-            String clientSecret)
-            throws KustvaktException, OAuthSystemException {
-
-        if (refreshTokenStr == null || refreshTokenStr.isEmpty()) {
-            throw new KustvaktException(StatusCodes.MISSING_PARAMETER,
-                    "Missing parameter: refresh_token",
-                    OAuth2Error.INVALID_REQUEST);
-        }
-
-        OAuth2Client oAuth2Client = clientService.authenticateClient(clientId, clientSecret);
-
-        RefreshToken refreshToken;
-        try {
-            refreshToken = refreshDao.retrieveRefreshToken(refreshTokenStr);
-        }
-        catch (NoResultException e) {
-            throw new KustvaktException(StatusCodes.INVALID_REFRESH_TOKEN,
-                    "Refresh token is not found", OAuth2Error.INVALID_GRANT);
-        }
-
-        if (!clientId.equals(refreshToken.getClient().getId())) {
-            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
-                    "Client " + clientId + " is not authorized",
-                    OAuth2Error.INVALID_CLIENT);
-        }
-        else if (refreshToken.isRevoked()) {
-            throw new KustvaktException(StatusCodes.INVALID_REFRESH_TOKEN,
-                    "Refresh token has been revoked",
-                    OAuth2Error.INVALID_GRANT);
-        }
-        else if (ZonedDateTime.now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE))
-                .isAfter(refreshToken.getExpiryDate())) {
-            throw new KustvaktException(StatusCodes.INVALID_REFRESH_TOKEN,
-                    "Refresh token is expired", OAuth2Error.INVALID_GRANT);
-        }
-
-        Set<AccessScope> tokenScopes =
-                new HashSet<>(refreshToken.getScopes());
-        if (requestScopes != null && !requestScopes.isEmpty()) {
-            tokenScopes =
-                    scopeService.verifyRefreshScope(requestScopes, tokenScopes);
-            requestScopes = scopeService
-                    .convertAccessScopesToStringSet(tokenScopes);
-        }
-
-        // revoke the refresh token and all access tokens associated to it
-        revokeRefreshToken(refreshTokenStr);
-
-        return createsAccessTokenResponse(requestScopes, tokenScopes, clientId,
-                refreshToken.getUserId(),
-                refreshToken.getUserAuthenticationTime(), oAuth2Client);
-
-        // without new refresh token
-        // return createsAccessTokenResponse(scopes, requestedScopes,
-        // clientId,
-        // refreshToken.getUserId(),
-        // refreshToken.getUserAuthenticationTime(), refreshToken);
-    }
-
-    /**
-     * Issues an access token for the specified client if the
-     * authorization code is valid and client successfully
-     * authenticates.
-     * 
-     * @param code
-     *            authorization code, required
-     * @param redirectUri
-     *            client redirect uri, required if specified in the
-     *            authorization request
-     * @param clientId
-     *            client id, required
-     * @param clientSecret
-     *            client secret, required
-     * @return an {@link OAuthResponse}
-     * @throws OAuthSystemException
-     * @throws KustvaktException
-     */
-    private OAuthResponse requestAccessTokenWithAuthorizationCode (String code,
-            String redirectUri, String clientId, String clientSecret)
-            throws OAuthSystemException, KustvaktException {
-        Authorization authorization = retrieveAuthorization(code, redirectUri,
-                clientId, clientSecret);
-
-        Set<String> scopes = scopeService
-                .convertAccessScopesToStringSet(authorization.getScopes());
-        OAuth2Client oAuth2Client = clientService.retrieveClient(clientId);
-        return createsAccessTokenResponse(scopes, authorization.getScopes(),
-                authorization.getClientId(), authorization.getUserId(),
-                authorization.getUserAuthenticationTime(), oAuth2Client);
-    }
-
-    /**
-     * Third party apps must not be allowed to use password grant.
-     * MH: password grant is only allowed for trusted clients (korap
-     * frontend)
-     * 
-     * According to RFC 6749, client authentication is only required
-     * for confidential clients and whenever client credentials are
-     * provided. Moreover, client_id is optional for password grant,
-     * but without it, the authentication server cannot check the
-     * client type. To make sure that confidential clients
-     * authenticate, client_id is made required (similar to
-     * authorization code grant).
-     * 
-     * TODO: FORCE client secret
-     * 
-     * @param clientId
-     *            client_id, required
-     * @param clientSecret
-     *            client_secret, required if client_secret was issued
-     *            for the client in client registration.
-     * @param username
-     *            username, required
-     * @param password
-     *            password, required
-     * @param scopes
-     *            authorization scopes, optional
-     * @return an {@link OAuthResponse}
-     * @throws KustvaktException
-     * @throws OAuthSystemException
-     */
-    private OAuthResponse requestAccessTokenWithPassword (String clientId,
-            String clientSecret, String username, String password,
-            Set<String> scopes) throws KustvaktException, OAuthSystemException {
-
-        OAuth2Client client =
-                clientService.authenticateClient(clientId, clientSecret);
-        if (!client.isSuper()) {
-            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
-                    "Password grant is not allowed for third party clients",
-                    OAuth2Error.UNAUTHORIZED_CLIENT);
-        }
-
-        if (scopes == null || scopes.isEmpty()) {
-            scopes = new HashSet<String>(1);
-            scopes.add("all");
-            // scopes = config.getDefaultAccessScopes();
-        }
-
-        ZonedDateTime authenticationTime =
-                authenticateUser(username, password, scopes);
-
-        Set<AccessScope> accessScopes =
-                scopeService.convertToAccessScope(scopes);
-        
-        if (config.getOAuth2passwordAuthentication()
-                .equals(AuthenticationMethod.LDAP)) {
-            try {
-                //username = LdapAuth3.getEmail(username, config.getLdapConfig());
-                username = LdapAuth3.getUsername(username, config.getLdapConfig());
-            }
-            catch (LDAPException e) {
-                throw new KustvaktException(StatusCodes.LDAP_BASE_ERRCODE,
-                        e.getExceptionMessage());
-            }
-        }
-        
-        return createsAccessTokenResponse(scopes, accessScopes, clientId,
-                username, authenticationTime, client);
-    }
-
-    /**
-     * 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
-     *            authorization scopes, optional
-     * @return an {@link OAuthResponse}
-     * @throws KustvaktException
-     * @throws OAuthSystemException
-     */
-    protected OAuthResponse requestAccessTokenWithClientCredentials (
-            String clientId, String clientSecret, Set<String> scopes)
-            throws KustvaktException, OAuthSystemException {
-
-        if (clientSecret == null || clientSecret.isEmpty()) {
-            throw new KustvaktException(
-                    StatusCodes.CLIENT_AUTHENTICATION_FAILED,
-                    "Missing parameter: client_secret",
-                    OAuth2Error.INVALID_REQUEST);
-        }
-
-        // OAuth2Client client =
-        OAuth2Client oAuth2Client = 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));
-
-        scopes = scopeService.filterScopes(scopes,
-                config.getClientCredentialsScopes());
-        Set<AccessScope> accessScopes =
-                scopeService.convertToAccessScope(scopes);
-        return createsAccessTokenResponse(scopes, accessScopes, clientId, null,
-                authenticationTime,oAuth2Client);
-    }
-
-    /**
-     * Creates an OAuthResponse containing an access token of type
-     * Bearer. By default, MD generator is used to generates access
-     * token of 128 bit values, represented in hexadecimal comprising
-     * 32 bytes. The generated value is subsequently encoded in
-     * Base64.
-     * 
-     * <br /><br />
-     * Additionally, a refresh token is issued for confidential clients. 
-     * It can be used to request a new access token without requiring user
-     * re-authentication.
-     * 
-     * @param scopes
-     *            a set of access token scopes in String
-     * @param accessScopes
-     *            a set of access token scopes in {@link AccessScope}
-     * @param clientId
-     *            a client id
-     * @param userId
-     *            a user id
-     * @param authenticationTime
-     *            the user authentication time
-     * @return an {@link OAuthResponse}
-     * @throws OAuthSystemException
-     * @throws KustvaktException
-     */
-    private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
-            Set<AccessScope> accessScopes, String clientId, String userId,
-            ZonedDateTime authenticationTime, OAuth2Client client)
-            throws OAuthSystemException, KustvaktException {
-
-        String random = randomGenerator.createRandomCode();
-        random += randomGenerator.createRandomCode();
-        
-        if (clientService.isPublicClient(client)){
-            // refresh token == null, getAccessTokenLongExpiry
-            return createsAccessTokenResponse(scopes, accessScopes, clientId,
-                    userId, authenticationTime);
-            }
-        else {
-            // refresh token != null, getAccessTokenExpiry
-            // default refresh token expiry: 365 days in seconds
-            RefreshToken refreshToken = refreshDao.storeRefreshToken(random,
-                    userId, authenticationTime, client, accessScopes);
-            return createsAccessTokenResponse(scopes, accessScopes, clientId,
-                    userId, authenticationTime, refreshToken);
-        }
-    }
-
-    private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
-            Set<AccessScope> accessScopes, String clientId, String userId,
-            ZonedDateTime authenticationTime, RefreshToken refreshToken)
-            throws OAuthSystemException, KustvaktException {
-
-        String accessToken = randomGenerator.createRandomCode();
-        accessToken +=randomGenerator.createRandomCode();
-        tokenDao.storeAccessToken(accessToken, refreshToken, accessScopes,
-                userId, clientId, authenticationTime);
-
-        return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
-                .setAccessToken(accessToken)
-                .setTokenType(TokenType.BEARER.toString())
-                .setExpiresIn(String.valueOf(config.getAccessTokenExpiry()))
-                .setRefreshToken(refreshToken.getToken())
-                .setScope(String.join(" ", scopes)).buildJSONMessage();
-    }
-    
-    private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
-            Set<AccessScope> accessScopes, String clientId, String userId,
-            ZonedDateTime authenticationTime)
-            throws OAuthSystemException, KustvaktException {
-
-        String accessToken = randomGenerator.createRandomCode();
-        accessToken +=randomGenerator.createRandomCode();
-        tokenDao.storeAccessToken(accessToken, null, accessScopes,
-                userId, clientId, authenticationTime);
-
-        return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
-                .setAccessToken(accessToken)
-                .setTokenType(TokenType.BEARER.toString())
-                .setExpiresIn(String.valueOf(config.getAccessTokenLongExpiry()))
-                .setScope(String.join(" ", scopes)).buildJSONMessage();
-    }
-
-    public void revokeToken (OAuth2RevokeTokenRequest revokeTokenRequest)
-            throws KustvaktException {
-        String clientId = revokeTokenRequest.getClientId();
-        String clientSecret = revokeTokenRequest.getClientSecret();
-        String token = revokeTokenRequest.getToken();
-        String tokenType = revokeTokenRequest.getTokenType();
-
-        clientService.authenticateClient(clientId, clientSecret);
-        if (tokenType != null && tokenType.equals("refresh_token")) {
-            if (!revokeRefreshToken(token)) {
-                revokeAccessToken(token);
-            }
-            return;
-        }
-
-        if (!revokeAccessToken(token)) {
-            revokeRefreshToken(token);
-        }
-    }
-
-    private boolean revokeAccessToken (String token) throws KustvaktException {
-        try {
-            AccessToken accessToken = tokenDao.retrieveAccessToken(token);
-            revokeAccessToken(accessToken);
-            return true;
-        }
-        catch (KustvaktException e) {
-            if (!e.getStatusCode().equals(StatusCodes.INVALID_ACCESS_TOKEN)) {
-                return false;
-            }
-            throw e;
-        }
-    }
-    
-    private void revokeAccessToken (AccessToken accessToken)
-            throws KustvaktException {
-        if (accessToken != null){
-            accessToken.setRevoked(true);
-            tokenDao.updateAccessToken(accessToken);
-        }
-    }
-
-    private boolean revokeRefreshToken (String token) throws KustvaktException {
-        RefreshToken refreshToken = null;
-        try {
-            refreshToken = refreshDao.retrieveRefreshToken(token);
-        }
-        catch (NoResultException e) {
-            return false;
-        }
-
-        return revokeRefreshToken(refreshToken);
-    }
-
-    public boolean revokeRefreshToken (RefreshToken refreshToken)
-            throws KustvaktException {
-        if (refreshToken != null){
-            refreshToken.setRevoked(true);
-            refreshDao.updateRefreshToken(refreshToken);
-    
-            Set<AccessToken> accessTokenList = refreshToken.getAccessTokens();
-            for (AccessToken accessToken : accessTokenList) {
-                accessToken.setRevoked(true);
-                tokenDao.updateAccessToken(accessToken);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    public void revokeAllClientTokensViaSuperClient (String username,
-            OAuth2RevokeAllTokenSuperRequest revokeTokenRequest)
-            throws KustvaktException {
-        String superClientId = revokeTokenRequest.getSuperClientId();
-        String superClientSecret = revokeTokenRequest.getSuperClientSecret();
-
-        OAuth2Client superClient = clientService
-                .authenticateClient(superClientId, superClientSecret);
-        if (!superClient.isSuper()) {
-            throw new KustvaktException(
-                    StatusCodes.CLIENT_AUTHENTICATION_FAILED);
-        }
-
-        String clientId = revokeTokenRequest.getClientId();
-        revokeAllClientTokensForUser(clientId, username);
-    }
-    
-    public void revokeAllClientTokensForUser (String clientId, String username)
-            throws KustvaktException {
-        OAuth2Client client = clientService.retrieveClient(clientId);
-        if (clientService.isPublicClient(client)) {
-            List<AccessToken> accessTokens =
-                    tokenDao.retrieveAccessTokenByClientId(clientId, username);
-            for (AccessToken t : accessTokens) {
-                revokeAccessToken(t);
-            }
-        }
-        else {
-            List<RefreshToken> refreshTokens = refreshDao
-                    .retrieveRefreshTokenByClientId(clientId, username);
-            for (RefreshToken r : refreshTokens) {
-                revokeRefreshToken(r);
-            }
-        }
-    }
-    
-    public void revokeTokensViaSuperClient (String username,
-            OAuth2RevokeTokenSuperRequest revokeTokenRequest) throws KustvaktException {
-        String superClientId = revokeTokenRequest.getSuperClientId();
-        String superClientSecret = revokeTokenRequest.getSuperClientSecret();
-
-        OAuth2Client superClient = clientService
-                .authenticateClient(superClientId, superClientSecret);
-        if (!superClient.isSuper()) {
-            throw new KustvaktException(
-                    StatusCodes.CLIENT_AUTHENTICATION_FAILED);
-        }
-        
-        String token = revokeTokenRequest.getToken();
-        RefreshToken refreshToken = refreshDao.retrieveRefreshToken(token, username);
-        if (!revokeRefreshToken(refreshToken)){
-            AccessToken accessToken = tokenDao.retrieveAccessToken(token, username);
-            revokeAccessToken(accessToken);
-        }
-    }
-    
-    public List<OAuth2TokenDto> listUserRefreshToken (String username, String superClientId,
-            String superClientSecret, String clientId) throws KustvaktException {
-        
-        OAuth2Client client = clientService.authenticateClient(superClientId, superClientSecret);
-        if (!client.isSuper()) {
-            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
-                    "Only super client is allowed.",
-                    OAuth2Error.UNAUTHORIZED_CLIENT);
-        }
-
-        List<RefreshToken> tokens = refreshDao.retrieveRefreshTokenByUser(username, clientId);
-        List<OAuth2TokenDto> dtoList = new ArrayList<>(tokens.size());
-        for (RefreshToken t : tokens){
-            OAuth2Client tokenClient = t.getClient();
-            if (tokenClient.getId().equals(client.getId())){
-                continue;
-            }
-            OAuth2TokenDto dto = new OAuth2TokenDto();
-            dto.setClientId(tokenClient.getId());
-            dto.setClientName(tokenClient.getName());
-            dto.setClientUrl(tokenClient.getUrl());
-            dto.setClientDescription(tokenClient.getDescription());
-            
-            DateTimeFormatter f = DateTimeFormatter.ISO_DATE_TIME;
-            dto.setCreatedDate(t.getCreatedDate().format(f));
-            long difference = ChronoUnit.SECONDS.between(ZonedDateTime.now(), t.getExpiryDate());
-            dto.setExpiresIn(difference);
-            
-            dto.setUserAuthenticationTime(
-                    t.getUserAuthenticationTime().format(f));
-            dto.setToken(t.getToken());
-            
-            Set<AccessScope> accessScopes = t.getScopes();
-            Set<String> scopes = new HashSet<>(accessScopes.size());
-            for (AccessScope s : accessScopes){
-                scopes.add(s.getId().toString());
-            }
-            dto.setScope(scopes);
-            dtoList.add(dto);
-        }
-        return dtoList;
-    }
-    
-    public List<OAuth2TokenDto> listUserAccessToken (String username, String superClientId,
-            String superClientSecret, String clientId) throws KustvaktException {
-        
-        OAuth2Client superClient = clientService.authenticateClient(superClientId, superClientSecret);
-        if (!superClient.isSuper()) {
-            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
-                    "Only super client is allowed.",
-                    OAuth2Error.UNAUTHORIZED_CLIENT);
-        }
-
-        List<AccessToken> tokens =
-                tokenDao.retrieveAccessTokenByUser(username, clientId);
-        List<OAuth2TokenDto> dtoList = new ArrayList<>(tokens.size());
-        for (AccessToken t : tokens){
-            OAuth2Client tokenClient = t.getClient();
-            if (tokenClient.getId().equals(superClient.getId())){
-                continue;
-            }
-            OAuth2TokenDto dto = new OAuth2TokenDto();
-            dto.setClientId(tokenClient.getId());
-            dto.setClientName(tokenClient.getName());
-            dto.setClientUrl(tokenClient.getUrl());
-            dto.setClientDescription(tokenClient.getDescription());
-            
-            DateTimeFormatter f = DateTimeFormatter.ISO_DATE_TIME;
-            dto.setCreatedDate(t.getCreatedDate().format(f));
-            
-            long difference = ChronoUnit.SECONDS.between(ZonedDateTime.now(), t.getExpiryDate());
-            dto.setExpiresIn(difference);
-                    
-            dto.setUserAuthenticationTime(
-                    t.getUserAuthenticationTime().format(f));
-            dto.setToken(t.getToken());
-            
-            Set<AccessScope> accessScopes = t.getScopes();
-            Set<String> scopes = new HashSet<>(accessScopes.size());
-            for (AccessScope s : accessScopes){
-                scopes.add(s.getId().toString());
-            }
-            dto.setScope(scopes);
-            dtoList.add(dto);
-        }
-        return dtoList;
-    }
-   
-}
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 93692ad..e92c2be 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
@@ -71,7 +71,7 @@
  * @author margaretha
  *
  */
-@Service
+//@Service
 public class OpenIdTokenService extends OAuth2TokenService {
 
     @Autowired
@@ -79,7 +79,7 @@
     @Autowired
     private RefreshTokenDao refreshDao;
 
-    public AccessTokenResponse requestAccessToken (TokenRequest tokenRequest)
+    public AccessTokenResponse requestAccessTokenWithOpenID (TokenRequest tokenRequest)
             throws KustvaktException {
         AuthorizationGrant grant = tokenRequest.getAuthorizationGrant();
         GrantType grantType = grant.getType();
@@ -88,13 +88,13 @@
         ClientID clientId = tokenRequest.getClientID();
 
         if (grantType.equals(GrantType.AUTHORIZATION_CODE)) {
-            return requestAccessTokenWithAuthorizationCode(grant,
+            return requestAccessTokenWithAuthorizationCodeAndOpenID(grant,
                     clientAuthentication, clientId);
         }
         else if (grantType.equals(GrantType.PASSWORD)) {
             ResourceOwnerPasswordCredentialsGrant passwordGrant =
                     (ResourceOwnerPasswordCredentialsGrant) grant;
-            return requestAccessTokenWithPassword(passwordGrant.getUsername(),
+            return requestAccessTokenWithPasswordAndOpenID(passwordGrant.getUsername(),
                     passwordGrant.getPassword().getValue(),
                     tokenRequest.getScope(), clientAuthentication, clientId);
         }
@@ -133,7 +133,7 @@
      * @return
      * @throws KustvaktException
      */
-    private AccessTokenResponse requestAccessTokenWithPassword (String username,
+    private AccessTokenResponse requestAccessTokenWithPasswordAndOpenID (String username,
             String password, Scope scope,
             ClientAuthentication clientAuthentication, ClientID clientId)
             throws KustvaktException {
@@ -193,7 +193,7 @@
                 clientIdStr, username, authenticationTime, null);
     }
 
-    private AccessTokenResponse requestAccessTokenWithAuthorizationCode (
+    private AccessTokenResponse requestAccessTokenWithAuthorizationCodeAndOpenID (
             AuthorizationGrant grant, ClientAuthentication clientAuthentication,
             ClientID clientId) throws KustvaktException {
         AuthorizationCodeGrant codeGrant = (AuthorizationCodeGrant) grant;
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
index 819a839..55d85ab 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
@@ -35,7 +35,6 @@
 import de.ids_mannheim.korap.oauth2.entity.Authorization;
 import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
 import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
-import de.ids_mannheim.korap.oauth2.oltu.service.OltuTokenService;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
 
@@ -67,7 +66,7 @@
 //                    UrlValidator.NO_FRAGMENTS + UrlValidator.ALLOW_LOCAL_URLS);
 
     @Autowired
-    private OltuTokenService tokenService;
+    private OAuth2TokenService tokenService;
     @Autowired
     private InstalledPluginDao pluginDao;
     @Autowired
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 9647748..c809daa 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
@@ -1,22 +1,60 @@
 package de.ids_mannheim.korap.oauth2.service;
 
+import java.net.URI;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.oltu.oauth2.as.response.OAuthASResponse;
 import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.apache.oltu.oauth2.common.message.types.TokenType;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
+import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.GrantType;
+import com.nimbusds.oauth2.sdk.RefreshTokenGrant;
+import com.nimbusds.oauth2.sdk.ResourceOwnerPasswordCredentialsGrant;
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretPost;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.unboundid.ldap.sdk.LDAPException;
+
 import de.ids_mannheim.korap.authentication.AuthenticationManager;
+import de.ids_mannheim.korap.authentication.LdapAuth3;
 import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.config.FullConfiguration;
+import de.ids_mannheim.korap.constant.AuthenticationMethod;
+import de.ids_mannheim.korap.encryption.RandomCodeGenerator;
 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.dao.RefreshTokenDao;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2TokenDto;
+import de.ids_mannheim.korap.oauth2.entity.AccessScope;
+import de.ids_mannheim.korap.oauth2.entity.AccessToken;
 import de.ids_mannheim.korap.oauth2.entity.Authorization;
+import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
+import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
+import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeAllTokenSuperRequest;
+import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeTokenRequest;
+import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeTokenSuperRequest;
+import jakarta.persistence.NoResultException;
+import jakarta.ws.rs.core.Response.Status;
 
 /**
  * OAuth2TokenService manages business logic related to OAuth2
@@ -41,6 +79,14 @@
     protected FullConfiguration config;
     @Autowired
     private AuthenticationManager authenticationManager;
+    
+    @Autowired
+    private RandomCodeGenerator randomGenerator;
+
+    @Autowired
+    private AccessTokenDao tokenDao;
+    @Autowired
+    private RefreshTokenDao refreshDao;
 
     /**
      * RFC 6749:
@@ -103,4 +149,579 @@
         return authenticationTime;
     }
 
+    public OAuthResponse requestAccessToken (
+            TokenRequest tokenRequest, String clientId, String clientSecret)
+            throws KustvaktException, OAuthSystemException {
+
+        AuthorizationGrant authGrant = tokenRequest.getAuthorizationGrant();
+        GrantType grantType = authGrant.getType();
+        Scope scope = tokenRequest.getScope();
+        Set<String> scopeSet = new HashSet<>();
+        if (scope !=null)
+            scopeSet.addAll(scope.toStringList());
+        
+        if (grantType.equals(GrantType.AUTHORIZATION_CODE)) {
+            AuthorizationCodeGrant codeGrant = (AuthorizationCodeGrant) authGrant;
+            String authCode = codeGrant.getAuthorizationCode().getValue();
+            URI uri = codeGrant.getRedirectionURI();
+            String redirectionURI = (uri != null) ? uri.toString() : null;
+            
+            return requestAccessTokenWithAuthorizationCode(authCode,
+                    redirectionURI, clientId, clientSecret);
+        }
+        else if (grantType.equals(GrantType.PASSWORD)) {
+            ResourceOwnerPasswordCredentialsGrant passwordGrant =
+                    (ResourceOwnerPasswordCredentialsGrant) authGrant;
+            String username = passwordGrant.getUsername();
+            String password = passwordGrant.getPassword().getValue();
+            return requestAccessTokenWithPassword(clientId, clientSecret,
+                    username, password, scopeSet);
+        }
+        else if (grantType.equals(GrantType.CLIENT_CREDENTIALS)) {
+            return requestAccessTokenWithClientCredentials(clientId,
+                    clientSecret, scopeSet);
+        }
+        else if (grantType.equals(GrantType.REFRESH_TOKEN)) {
+            RefreshTokenGrant refreshGrant = (RefreshTokenGrant) authGrant;
+            String refreshToken = refreshGrant.getRefreshToken().getValue();
+            return requestAccessTokenWithRefreshToken(refreshToken, scopeSet,
+                    clientId, clientSecret);
+        }
+        else {
+            throw new KustvaktException(StatusCodes.UNSUPPORTED_GRANT_TYPE,
+                    grantType + " is not supported.",
+                    OAuth2Error.UNSUPPORTED_GRANT_TYPE);
+        }
+
+    }
+    
+
+    /**
+     * Revokes all access token associated with the given refresh
+     * token, and creates a new access token and a new refresh
+     * token with the same scopes. Thus, at one point of time,
+     * there is only one active access token associated with
+     * a refresh token.
+     * 
+     * Client authentication is done using the given client
+     * credentials.
+     * 
+     * TODO: should create a new refresh token when the old refresh
+     * token is used (DONE)
+     * 
+     * @param refreshTokenStr
+     * @param requestScopes
+     * @param clientId
+     * @param clientSecret
+     * @return if successful, a new access token
+     * @throws KustvaktException
+     * @throws OAuthSystemException
+     */
+    private OAuthResponse requestAccessTokenWithRefreshToken (
+            String refreshTokenStr, Set<String> requestScopes, String clientId,
+            String clientSecret)
+            throws KustvaktException, OAuthSystemException {
+
+        if (refreshTokenStr == null || refreshTokenStr.isEmpty()) {
+            throw new KustvaktException(StatusCodes.MISSING_PARAMETER,
+                    "Missing parameter: refresh_token",
+                    OAuth2Error.INVALID_REQUEST);
+        }
+
+        OAuth2Client oAuth2Client = clientService.authenticateClient(clientId, clientSecret);
+
+        RefreshToken refreshToken;
+        try {
+            refreshToken = refreshDao.retrieveRefreshToken(refreshTokenStr);
+        }
+        catch (NoResultException e) {
+            throw new KustvaktException(StatusCodes.INVALID_REFRESH_TOKEN,
+                    "Refresh token is not found", OAuth2Error.INVALID_GRANT);
+        }
+
+        if (!clientId.equals(refreshToken.getClient().getId())) {
+            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
+                    "Client " + clientId + " is not authorized",
+                    OAuth2Error.INVALID_CLIENT);
+        }
+        else if (refreshToken.isRevoked()) {
+            throw new KustvaktException(StatusCodes.INVALID_REFRESH_TOKEN,
+                    "Refresh token has been revoked",
+                    OAuth2Error.INVALID_GRANT);
+        }
+        else if (ZonedDateTime.now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE))
+                .isAfter(refreshToken.getExpiryDate())) {
+            throw new KustvaktException(StatusCodes.INVALID_REFRESH_TOKEN,
+                    "Refresh token is expired", OAuth2Error.INVALID_GRANT);
+        }
+
+        Set<AccessScope> tokenScopes =
+                new HashSet<>(refreshToken.getScopes());
+        if (requestScopes != null && !requestScopes.isEmpty()) {
+            tokenScopes =
+                    scopeService.verifyRefreshScope(requestScopes, tokenScopes);
+            requestScopes = scopeService
+                    .convertAccessScopesToStringSet(tokenScopes);
+        }
+
+        // revoke the refresh token and all access tokens associated to it
+        revokeRefreshToken(refreshTokenStr);
+
+        return createsAccessTokenResponse(requestScopes, tokenScopes, clientId,
+                refreshToken.getUserId(),
+                refreshToken.getUserAuthenticationTime(), oAuth2Client);
+
+        // without new refresh token
+        // return createsAccessTokenResponse(scopes, requestedScopes,
+        // clientId,
+        // refreshToken.getUserId(),
+        // refreshToken.getUserAuthenticationTime(), refreshToken);
+    }
+
+    /**
+     * Issues an access token for the specified client if the
+     * authorization code is valid and client successfully
+     * authenticates.
+     * 
+     * @param code
+     *            authorization code, required
+     * @param redirectionURI
+     *            client redirect uri, required if specified in the
+     *            authorization request
+     * @param clientId
+     *            client id, required
+     * @param clientSecret
+     *            client secret, required
+     * @return an {@link OAuthResponse}
+     * @throws OAuthSystemException
+     * @throws KustvaktException
+     */
+    private OAuthResponse requestAccessTokenWithAuthorizationCode (String code,
+            String redirectionURI, String clientId, String clientSecret)
+            throws OAuthSystemException, KustvaktException {
+        Authorization authorization = retrieveAuthorization(code, redirectionURI,
+                clientId, clientSecret);
+
+        Set<String> scopes = scopeService
+                .convertAccessScopesToStringSet(authorization.getScopes());
+        OAuth2Client oAuth2Client = clientService.retrieveClient(clientId);
+        return createsAccessTokenResponse(scopes, authorization.getScopes(),
+                authorization.getClientId(), authorization.getUserId(),
+                authorization.getUserAuthenticationTime(), oAuth2Client);
+    }
+
+    /**
+     * Third party apps must not be allowed to use password grant.
+     * MH: password grant is only allowed for trusted clients (korap
+     * frontend)
+     * 
+     * According to RFC 6749, client authentication is only required
+     * for confidential clients and whenever client credentials are
+     * provided. Moreover, client_id is optional for password grant,
+     * but without it, the authentication server cannot check the
+     * client type. To make sure that confidential clients
+     * authenticate, client_id is made required (similar to
+     * authorization code grant).
+     * 
+     * TODO: FORCE client secret
+     * 
+     * @param clientId
+     *            client_id, required
+     * @param clientSecret
+     *            client_secret, required if client_secret was issued
+     *            for the client in client registration.
+     * @param username
+     *            username, required
+     * @param password
+     *            password, required
+     * @param scopes
+     *            authorization scopes, optional
+     * @return an {@link OAuthResponse}
+     * @throws KustvaktException
+     * @throws OAuthSystemException
+     */
+    private OAuthResponse requestAccessTokenWithPassword (String clientId,
+            String clientSecret, String username, String password,
+            Set<String> scopes) throws KustvaktException, OAuthSystemException {
+
+        OAuth2Client client =
+                clientService.authenticateClient(clientId, clientSecret);
+        if (!client.isSuper()) {
+            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
+                    "Password grant is not allowed for third party clients",
+                    OAuth2Error.UNAUTHORIZED_CLIENT);
+        }
+
+        if (scopes == null || scopes.isEmpty()) {
+            scopes = new HashSet<String>(1);
+            scopes.add("all");
+            // scopes = config.getDefaultAccessScopes();
+        }
+
+        ZonedDateTime authenticationTime =
+                authenticateUser(username, password, scopes);
+
+        Set<AccessScope> accessScopes =
+                scopeService.convertToAccessScope(scopes);
+        
+        if (config.getOAuth2passwordAuthentication()
+                .equals(AuthenticationMethod.LDAP)) {
+            try {
+                //username = LdapAuth3.getEmail(username, config.getLdapConfig());
+                username = LdapAuth3.getUsername(username, config.getLdapConfig());
+            }
+            catch (LDAPException e) {
+                throw new KustvaktException(StatusCodes.LDAP_BASE_ERRCODE,
+                        e.getExceptionMessage());
+            }
+        }
+        
+        return createsAccessTokenResponse(scopes, accessScopes, clientId,
+                username, authenticationTime, client);
+    }
+
+    /**
+     * 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
+     *            authorization scopes, optional
+     * @return an {@link OAuthResponse}
+     * @throws KustvaktException
+     * @throws OAuthSystemException
+     */
+    protected OAuthResponse requestAccessTokenWithClientCredentials (
+            String clientId, String clientSecret, Set<String> scopes)
+            throws KustvaktException, OAuthSystemException {
+
+        if (clientSecret == null || clientSecret.isEmpty()) {
+            throw new KustvaktException(
+                    StatusCodes.CLIENT_AUTHENTICATION_FAILED,
+                    "Missing parameter: client_secret",
+                    OAuth2Error.INVALID_REQUEST);
+        }
+
+        // OAuth2Client client =
+        OAuth2Client oAuth2Client = 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));
+
+        scopes = scopeService.filterScopes(scopes,
+                config.getClientCredentialsScopes());
+        Set<AccessScope> accessScopes =
+                scopeService.convertToAccessScope(scopes);
+        return createsAccessTokenResponse(scopes, accessScopes, clientId, null,
+                authenticationTime,oAuth2Client);
+    }
+
+    /**
+     * Creates an OAuthResponse containing an access token of type
+     * Bearer. By default, MD generator is used to generates access
+     * token of 128 bit values, represented in hexadecimal comprising
+     * 32 bytes. The generated value is subsequently encoded in
+     * Base64.
+     * 
+     * <br /><br />
+     * Additionally, a refresh token is issued for confidential clients. 
+     * It can be used to request a new access token without requiring user
+     * re-authentication.
+     * 
+     * @param scopes
+     *            a set of access token scopes in String
+     * @param accessScopes
+     *            a set of access token scopes in {@link AccessScope}
+     * @param clientId
+     *            a client id
+     * @param userId
+     *            a user id
+     * @param authenticationTime
+     *            the user authentication time
+     * @return an {@link OAuthResponse}
+     * @throws OAuthSystemException
+     * @throws KustvaktException
+     */
+    private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
+            Set<AccessScope> accessScopes, String clientId, String userId,
+            ZonedDateTime authenticationTime, OAuth2Client client)
+            throws OAuthSystemException, KustvaktException {
+
+        String random = randomGenerator.createRandomCode();
+        random += randomGenerator.createRandomCode();
+        
+        if (clientService.isPublicClient(client)){
+            // refresh token == null, getAccessTokenLongExpiry
+            return createsAccessTokenResponse(scopes, accessScopes, clientId,
+                    userId, authenticationTime);
+            }
+        else {
+            // refresh token != null, getAccessTokenExpiry
+            // default refresh token expiry: 365 days in seconds
+            RefreshToken refreshToken = refreshDao.storeRefreshToken(random,
+                    userId, authenticationTime, client, accessScopes);
+            return createsAccessTokenResponse(scopes, accessScopes, clientId,
+                    userId, authenticationTime, refreshToken);
+        }
+    }
+
+    private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
+            Set<AccessScope> accessScopes, String clientId, String userId,
+            ZonedDateTime authenticationTime, RefreshToken refreshToken)
+            throws OAuthSystemException, KustvaktException {
+
+        String accessToken = randomGenerator.createRandomCode();
+        accessToken +=randomGenerator.createRandomCode();
+        tokenDao.storeAccessToken(accessToken, refreshToken, accessScopes,
+                userId, clientId, authenticationTime);
+
+        return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
+                .setAccessToken(accessToken)
+                .setTokenType(TokenType.BEARER.toString())
+                .setExpiresIn(String.valueOf(config.getAccessTokenExpiry()))
+                .setRefreshToken(refreshToken.getToken())
+                .setScope(String.join(" ", scopes)).buildJSONMessage();
+    }
+    
+    private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
+            Set<AccessScope> accessScopes, String clientId, String userId,
+            ZonedDateTime authenticationTime)
+            throws OAuthSystemException, KustvaktException {
+
+        String accessToken = randomGenerator.createRandomCode();
+        accessToken +=randomGenerator.createRandomCode();
+        tokenDao.storeAccessToken(accessToken, null, accessScopes,
+                userId, clientId, authenticationTime);
+
+        return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
+                .setAccessToken(accessToken)
+                .setTokenType(TokenType.BEARER.toString())
+                .setExpiresIn(String.valueOf(config.getAccessTokenLongExpiry()))
+                .setScope(String.join(" ", scopes)).buildJSONMessage();
+    }
+
+    public void revokeToken (OAuth2RevokeTokenRequest revokeTokenRequest)
+            throws KustvaktException {
+        String clientId = revokeTokenRequest.getClientId();
+        String clientSecret = revokeTokenRequest.getClientSecret();
+        String token = revokeTokenRequest.getToken();
+        String tokenType = revokeTokenRequest.getTokenType();
+
+        clientService.authenticateClient(clientId, clientSecret);
+        if (tokenType != null && tokenType.equals("refresh_token")) {
+            if (!revokeRefreshToken(token)) {
+                revokeAccessToken(token);
+            }
+            return;
+        }
+
+        if (!revokeAccessToken(token)) {
+            revokeRefreshToken(token);
+        }
+    }
+
+    private boolean revokeAccessToken (String token) throws KustvaktException {
+        try {
+            AccessToken accessToken = tokenDao.retrieveAccessToken(token);
+            revokeAccessToken(accessToken);
+            return true;
+        }
+        catch (KustvaktException e) {
+            if (!e.getStatusCode().equals(StatusCodes.INVALID_ACCESS_TOKEN)) {
+                return false;
+            }
+            throw e;
+        }
+    }
+    
+    private void revokeAccessToken (AccessToken accessToken)
+            throws KustvaktException {
+        if (accessToken != null){
+            accessToken.setRevoked(true);
+            tokenDao.updateAccessToken(accessToken);
+        }
+    }
+
+    private boolean revokeRefreshToken (String token) throws KustvaktException {
+        RefreshToken refreshToken = null;
+        try {
+            refreshToken = refreshDao.retrieveRefreshToken(token);
+        }
+        catch (NoResultException e) {
+            return false;
+        }
+
+        return revokeRefreshToken(refreshToken);
+    }
+
+    public boolean revokeRefreshToken (RefreshToken refreshToken)
+            throws KustvaktException {
+        if (refreshToken != null){
+            refreshToken.setRevoked(true);
+            refreshDao.updateRefreshToken(refreshToken);
+    
+            Set<AccessToken> accessTokenList = refreshToken.getAccessTokens();
+            for (AccessToken accessToken : accessTokenList) {
+                accessToken.setRevoked(true);
+                tokenDao.updateAccessToken(accessToken);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public void revokeAllClientTokensViaSuperClient (String username,
+            OAuth2RevokeAllTokenSuperRequest revokeTokenRequest)
+            throws KustvaktException {
+        String superClientId = revokeTokenRequest.getSuperClientId();
+        String superClientSecret = revokeTokenRequest.getSuperClientSecret();
+
+        OAuth2Client superClient = clientService
+                .authenticateClient(superClientId, superClientSecret);
+        if (!superClient.isSuper()) {
+            throw new KustvaktException(
+                    StatusCodes.CLIENT_AUTHENTICATION_FAILED);
+        }
+
+        String clientId = revokeTokenRequest.getClientId();
+        revokeAllClientTokensForUser(clientId, username);
+    }
+    
+    public void revokeAllClientTokensForUser (String clientId, String username)
+            throws KustvaktException {
+        OAuth2Client client = clientService.retrieveClient(clientId);
+        if (clientService.isPublicClient(client)) {
+            List<AccessToken> accessTokens =
+                    tokenDao.retrieveAccessTokenByClientId(clientId, username);
+            for (AccessToken t : accessTokens) {
+                revokeAccessToken(t);
+            }
+        }
+        else {
+            List<RefreshToken> refreshTokens = refreshDao
+                    .retrieveRefreshTokenByClientId(clientId, username);
+            for (RefreshToken r : refreshTokens) {
+                revokeRefreshToken(r);
+            }
+        }
+    }
+    
+    public void revokeTokensViaSuperClient (String username,
+            OAuth2RevokeTokenSuperRequest revokeTokenRequest) throws KustvaktException {
+        String superClientId = revokeTokenRequest.getSuperClientId();
+        String superClientSecret = revokeTokenRequest.getSuperClientSecret();
+
+        OAuth2Client superClient = clientService
+                .authenticateClient(superClientId, superClientSecret);
+        if (!superClient.isSuper()) {
+            throw new KustvaktException(
+                    StatusCodes.CLIENT_AUTHENTICATION_FAILED);
+        }
+        
+        String token = revokeTokenRequest.getToken();
+        RefreshToken refreshToken = refreshDao.retrieveRefreshToken(token, username);
+        if (!revokeRefreshToken(refreshToken)){
+            AccessToken accessToken = tokenDao.retrieveAccessToken(token, username);
+            revokeAccessToken(accessToken);
+        }
+    }
+    
+    public List<OAuth2TokenDto> listUserRefreshToken (String username, String superClientId,
+            String superClientSecret, String clientId) throws KustvaktException {
+        
+        OAuth2Client client = clientService.authenticateClient(superClientId, superClientSecret);
+        if (!client.isSuper()) {
+            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
+                    "Only super client is allowed.",
+                    OAuth2Error.UNAUTHORIZED_CLIENT);
+        }
+
+        List<RefreshToken> tokens = refreshDao.retrieveRefreshTokenByUser(username, clientId);
+        List<OAuth2TokenDto> dtoList = new ArrayList<>(tokens.size());
+        for (RefreshToken t : tokens){
+            OAuth2Client tokenClient = t.getClient();
+            if (tokenClient.getId().equals(client.getId())){
+                continue;
+            }
+            OAuth2TokenDto dto = new OAuth2TokenDto();
+            dto.setClientId(tokenClient.getId());
+            dto.setClientName(tokenClient.getName());
+            dto.setClientUrl(tokenClient.getUrl());
+            dto.setClientDescription(tokenClient.getDescription());
+            
+            DateTimeFormatter f = DateTimeFormatter.ISO_DATE_TIME;
+            dto.setCreatedDate(t.getCreatedDate().format(f));
+            long difference = ChronoUnit.SECONDS.between(ZonedDateTime.now(), t.getExpiryDate());
+            dto.setExpiresIn(difference);
+            
+            dto.setUserAuthenticationTime(
+                    t.getUserAuthenticationTime().format(f));
+            dto.setToken(t.getToken());
+            
+            Set<AccessScope> accessScopes = t.getScopes();
+            Set<String> scopes = new HashSet<>(accessScopes.size());
+            for (AccessScope s : accessScopes){
+                scopes.add(s.getId().toString());
+            }
+            dto.setScope(scopes);
+            dtoList.add(dto);
+        }
+        return dtoList;
+    }
+    
+    public List<OAuth2TokenDto> listUserAccessToken (String username, String superClientId,
+            String superClientSecret, String clientId) throws KustvaktException {
+        
+        OAuth2Client superClient = clientService.authenticateClient(superClientId, superClientSecret);
+        if (!superClient.isSuper()) {
+            throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
+                    "Only super client is allowed.",
+                    OAuth2Error.UNAUTHORIZED_CLIENT);
+        }
+
+        List<AccessToken> tokens =
+                tokenDao.retrieveAccessTokenByUser(username, clientId);
+        List<OAuth2TokenDto> dtoList = new ArrayList<>(tokens.size());
+        for (AccessToken t : tokens){
+            OAuth2Client tokenClient = t.getClient();
+            if (tokenClient.getId().equals(superClient.getId())){
+                continue;
+            }
+            OAuth2TokenDto dto = new OAuth2TokenDto();
+            dto.setClientId(tokenClient.getId());
+            dto.setClientName(tokenClient.getName());
+            dto.setClientUrl(tokenClient.getUrl());
+            dto.setClientDescription(tokenClient.getDescription());
+            
+            DateTimeFormatter f = DateTimeFormatter.ISO_DATE_TIME;
+            dto.setCreatedDate(t.getCreatedDate().format(f));
+            
+            long difference = ChronoUnit.SECONDS.between(ZonedDateTime.now(), t.getExpiryDate());
+            dto.setExpiresIn(difference);
+                    
+            dto.setUserAuthenticationTime(
+                    t.getUserAuthenticationTime().format(f));
+            dto.setToken(t.getToken());
+            
+            Set<AccessScope> accessScopes = t.getScopes();
+            Set<String> scopes = new HashSet<>(accessScopes.size());
+            for (AccessScope s : accessScopes){
+                scopes.add(s.getId().toString());
+            }
+            dto.setScope(scopes);
+            dtoList.add(dto);
+        }
+        return dtoList;
+    }
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
index 6e58ac8..5792be4 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
@@ -4,17 +4,30 @@
 import java.net.URISyntaxException;
 import java.time.ZonedDateTime;
 
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
 import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse;
+import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.ClientCredentialsGrant;
 import com.nimbusds.oauth2.sdk.OAuth2Error;
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretPost;
+import com.nimbusds.oauth2.sdk.id.ClientID;
 
 import de.ids_mannheim.korap.constant.OAuth2Scope;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.service.OAuth2AuthorizationService;
 import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
+import de.ids_mannheim.korap.oauth2.service.OAuth2TokenService;
 import de.ids_mannheim.korap.security.context.TokenContext;
 import de.ids_mannheim.korap.web.OAuth2ResponseHandler;
 import de.ids_mannheim.korap.web.filter.APIVersionFilter;
@@ -57,7 +70,8 @@
     @Autowired
     private OAuth2ResponseHandler responseHandler;
 
-    
+    @Autowired
+    private OAuth2TokenService tokenService;
     @Autowired
     private OAuth2AuthorizationService authorizationService;
     
@@ -237,42 +251,83 @@
      *         if successful, an error code and an error description
      *         otherwise.
      */
-//    @POST
-//    @Path("token")
-//    @ResourceFilters({APIVersionFilter.class})
-//    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-//    public Response requestAccessToken (@Context HttpServletRequest request,
-//            @FormParam("grant_type") String grantType,
-//            MultivaluedMap<String, String> form) {
-//
-//        try {
-//            boolean grantTypeExist = grantType != null && !grantType.isEmpty();
-//            AbstractOAuthTokenRequest oAuthRequest = null;
-//            if (grantTypeExist && grantType
-//                    .equals(GrantType.CLIENT_CREDENTIALS.toString())) {
-//                oAuthRequest = new OAuthTokenRequest(
-//                        new FormRequestWrapper(request, form));
-//            }
-//            else {
-//                oAuthRequest = new OAuthUnauthenticatedTokenRequest(
-//                        new FormRequestWrapper(request, form));
-//            }
-//
-//            OAuthResponse oAuthResponse =
-//                    tokenService.requestAccessToken(oAuthRequest);
-//
-//            return responseHandler.createResponse(oAuthResponse);
-//        }
-//        catch (KustvaktException e) {
-//            throw responseHandler.throwit(e);
-//        }
-//        catch (OAuthProblemException e) {
-//            throw responseHandler.throwit(e);
-//        }
-//        catch (OAuthSystemException e) {
-//            throw responseHandler.throwit(e);
-//        }
-//    }
+    @POST
+    @Path("token")
+    @ResourceFilters({APIVersionFilter.class})
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public Response requestAccessToken (@Context HttpServletRequest request,
+            @FormParam("client_id") String clientId,
+            @FormParam("client_secret") String clientSecret,
+            MultivaluedMap<String, String> form) {
+
+        OAuthResponse oAuthResponse = null;
+        try {
+            URI requestURI;
+            UriBuilder builder = UriBuilder.fromPath(
+                    request.getRequestURL().toString());
+            for (String key : form.keySet()) {
+                builder.queryParam(key, form.get(key).toArray());
+            }
+            requestURI = builder.build();
+            
+            try {
+                AuthorizationGrant authGrant = AuthorizationGrant.parse(form);  
+                
+                ClientAuthentication clientAuth = null;
+                String authorizationHeader = request.getHeader("Authorization");
+                if (authorizationHeader!=null && !authorizationHeader.isEmpty() ) {
+                    clientAuth = ClientSecretBasic.parse(authorizationHeader);
+                }
+                else if (authGrant instanceof ClientCredentialsGrant) {
+                    // this doesn't allow public clients
+                    clientAuth = ClientSecretPost.parse(form);
+                }
+                
+                TokenRequest tokenRequest = null;
+                if (clientAuth!=null) {
+                    ClientAuthenticationMethod method = clientAuth.getMethod();
+                    if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)) {
+                        ClientSecretBasic basic = (ClientSecretBasic) clientAuth;
+                        clientSecret = basic.getClientSecret().getValue();
+                        clientId = basic.getClientID().getValue();
+                    }
+                    else if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_POST)) {
+                        ClientSecretPost post = (ClientSecretPost) clientAuth;
+                        clientSecret = post.getClientSecret().getValue();
+                        clientId = post.getClientID().getValue();
+                    }
+                    
+                    tokenRequest = new TokenRequest(requestURI,
+                            clientAuth,
+                            AuthorizationGrant.parse(form),
+                            Scope.parse(form.getFirst("scope")));
+                }
+                else {
+                    // requires ClientAuthentication for client_credentials grant
+                    tokenRequest = new TokenRequest(requestURI,
+                        new ClientID(clientId),
+                        AuthorizationGrant.parse(form),
+                        Scope.parse(form.getFirst("scope")));
+                }
+            
+                oAuthResponse = tokenService.requestAccessToken(tokenRequest,
+                        clientId, clientSecret);
+            }
+            catch (ParseException | IllegalArgumentException e) {
+                throw new KustvaktException(StatusCodes.INVALID_REQUEST,
+                        e.getMessage(), OAuth2Error.INVALID_REQUEST); 
+            }
+            
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+        catch (OAuthSystemException e) {
+            throw responseHandler.throwit(e);
+        }
+        
+        return responseHandler.createResponse(oAuthResponse);
+    }
 
     /**
      * Revokes either an access token or a refresh token. Revoking a
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
index dea240c..f2c60d2 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
@@ -64,7 +64,7 @@
 
     @Autowired
     private OpenIdAuthorizationService authzService;
-    @Autowired
+    //@Autowired
     private OpenIdTokenService tokenService;
     @Autowired
     private JWKService jwkService;
@@ -197,7 +197,7 @@
 
             TokenRequest tokenRequest = TokenRequest.parse(httpRequest);
             AccessTokenResponse tokenResponse =
-                    tokenService.requestAccessToken(tokenRequest);
+                    tokenService.requestAccessTokenWithOpenID(tokenRequest);
             return openIdResponseHandler.createResponse(tokenResponse,
                     Status.OK);
         }
diff --git a/full/src/main/resources/basic-config.xml b/full/src/main/resources/basic-config.xml
index 87cb8f7..c8cfdaa 100644
--- a/full/src/main/resources/basic-config.xml
+++ b/full/src/main/resources/basic-config.xml
@@ -221,12 +221,6 @@
 	<bean id="oauth2ResponseHandler" class="de.ids_mannheim.korap.web.OAuth2ResponseHandler">
 	</bean>
 
-	<bean id="mdGenerator" class="org.apache.oltu.oauth2.as.issuer.MD5Generator">
-	</bean>
-	<bean id="oauthIssuer" class="org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl">
-		<constructor-arg index="0" ref="mdGenerator" />
-	</bean>
-
 	<bean id="kustvakt_userdb" class="de.ids_mannheim.korap.handlers.EntityDao">
 		<constructor-arg ref="kustvakt_db" />
 	</bean>
diff --git a/full/src/main/resources/default-config.xml b/full/src/main/resources/default-config.xml
index a375b44..fa3ed22 100644
--- a/full/src/main/resources/default-config.xml
+++ b/full/src/main/resources/default-config.xml
@@ -242,12 +242,6 @@
 	<bean id="oauth2ResponseHandler" class="de.ids_mannheim.korap.web.OAuth2ResponseHandler">
 	</bean>
 
-	<bean id="mdGenerator" class="org.apache.oltu.oauth2.as.issuer.MD5Generator">
-	</bean>
-	<bean id="oauthIssuer" class="org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl">
-		<constructor-arg index="0" ref="mdGenerator" />
-	</bean>
-
 	<bean name="kustvakt_encryption" class="de.ids_mannheim.korap.encryption.KustvaktEncryption">
 		<constructor-arg ref="kustvakt_config" />
 	</bean>
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
index 8ac612d..a529090 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
@@ -78,9 +78,6 @@
         MultivaluedMap<String, String> params =
                 getQueryParamsFromURI(response.getLocation());
         String code = params.get("code").get(0);
-        String scopes = params.get("scope").get(0);
-
-        assertEquals(scopes, "search");
 
         response = requestTokenWithAuthorizationCodeAndForm(
                 confidentialClientId, clientSecret, code);
@@ -362,6 +359,20 @@
     public void testRequestTokenPasswordGrantMissingClientSecret ()
             throws KustvaktException {
         Response response =
+                requestTokenWithDoryPassword(confidentialClientId, null);
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+
+        String entity = response.readEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
+                node.at("/error").asText());
+        assertNotNull(node.at("/error_description").asText());
+    }
+    
+    @Test
+    public void testRequestTokenPasswordGrantEmptyClientSecret ()
+            throws KustvaktException {
+        Response response =
                 requestTokenWithDoryPassword(confidentialClientId, "");
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
 
@@ -384,8 +395,21 @@
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
                 node.at("/error").asText());
-        assertEquals("Missing parameters: client_id",
-                node.at("/error_description").asText());
+        assertNotNull(node.at("/error_description").asText());
+    }
+    
+    @Test
+    public void testRequestTokenPasswordGrantEmptyClientId ()
+            throws KustvaktException {
+        Response response =
+                requestTokenWithDoryPassword("", clientSecret);
+        String entity = response.readEntity(String.class);
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
+                node.at("/error").asText());
+        assertNotNull(node.at("/error_description").asText());
     }
 
     @Test
@@ -398,6 +422,7 @@
         form.param("client_secret", "secret");
         Response response = requestToken(form);
         String entity = response.readEntity(String.class);
+        System.out.println(entity);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
         JsonNode node = JsonUtils.readTree(entity);
@@ -428,8 +453,7 @@
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
                 node.at("/error").asText());
-        assertEquals("Missing parameters: client_secret",
-                node.at("/error_description").asText());
+        assertNotNull(node.at("/error_description").asText());
     }
 
     @Test
@@ -486,8 +510,7 @@
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
 
         JsonNode node = JsonUtils.readTree(entity);
-        assertEquals("Invalid grant_type parameter value",
-                node.get("error_description").asText());
+        assertNotNull(node.get("error_description").asText());
         assertEquals(OAuthError.TokenResponse.INVALID_REQUEST,
                 node.get("error").asText());
     }
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java
index bb5440c..a5189d0 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java
@@ -234,7 +234,9 @@
         Form form = new Form();
         form.param("grant_type", "password");
         form.param("client_id", clientId);
-        form.param("client_secret", clientSecret);
+        if (clientSecret !=null && !clientSecret.isEmpty()) {
+            form.param("client_secret", clientSecret);
+        }
         form.param("username", username);
         form.param("password", password);
 
@@ -262,7 +264,7 @@
 
         String entity = response.readEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
-        assertEquals(OAuth2Error.INVALID_GRANT, node.at("/error").asText());
+        assertEquals(OAuth2Error.INVALID_GRANT.getCode(), node.at("/error").asText());
         assertEquals("Refresh token has been revoked",
                 node.at("/error_description").asText());
     }
diff --git a/full/src/test/resources/test-config-icc.xml b/full/src/test/resources/test-config-icc.xml
index 383f378..466b052 100644
--- a/full/src/test/resources/test-config-icc.xml
+++ b/full/src/test/resources/test-config-icc.xml
@@ -229,12 +229,6 @@
 	<bean id="oauth2ResponseHandler" class="de.ids_mannheim.korap.web.OAuth2ResponseHandler">
 	</bean>
 
-	<bean id="mdGenerator" class="org.apache.oltu.oauth2.as.issuer.MD5Generator">
-	</bean>
-	<bean id="oauthIssuer" class="org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl">
-		<constructor-arg index="0" ref="mdGenerator" />
-	</bean>
-
 	<bean name="kustvakt_encryption" class="de.ids_mannheim.korap.encryption.KustvaktEncryption">
 		<constructor-arg ref="kustvakt_config" />
 	</bean>
diff --git a/full/src/test/resources/test-config.xml b/full/src/test/resources/test-config.xml
index a85673b..2c16410 100644
--- a/full/src/test/resources/test-config.xml
+++ b/full/src/test/resources/test-config.xml
@@ -224,12 +224,6 @@
 	<bean id="oauth2ResponseHandler" class="de.ids_mannheim.korap.web.OAuth2ResponseHandler">
 	</bean>
 
-	<bean id="mdGenerator" class="org.apache.oltu.oauth2.as.issuer.MD5Generator">
-	</bean>
-	<bean id="oauthIssuer" class="org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl">
-		<constructor-arg index="0" ref="mdGenerator" />
-	</bean>
-
 	<bean name="kustvakt_encryption" class="de.ids_mannheim.korap.encryption.KustvaktEncryption">
 		<constructor-arg ref="kustvakt_config" />
 	</bean>