You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2019/06/18 12:39:45 UTC

[servicecomb-fence] branch master updated (3d0ee93 -> fd6e71c)

This is an automated email from the ASF dual-hosted git repository.

liubao pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git.


    from 3d0ee93  [SCB-1293]update readme and seperate english and zh_cn
     new d16bba4  [SCB-1319]refactor code to better satisfy session token & jwt token authentication
     new b078c95  [SCB-1319]update docs and add design diagram
     new fd6e71c  Merge pull request #3 from liubao68/master

The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 README.md                                          |   9 ++
 README_ZH.md                                       |   9 ++
 .../server/PasswordTokenGranter.java               |  38 +++-----
 .../server/RefreshTokenTokenGranter.java           |  36 ++-----
 .../authentication/server/TokenResponse.java       |  32 +++---
 .../authentication/token/TokenConfiguration.java   |  30 +++---
 .../token/AbstractOpenIDTokenStore.java            |  52 ++++++++++
 .../token/InMemoryOpenIDTokenStore.java            |  51 ++++++++++
 .../token/InMemorySessionIDTokenStore.java         |  42 --------
 .../servicecomb/authentication/token/JWTToken.java |  65 +------------
 .../token/{JWTToken.java => JWTTokenImpl.java}     |   8 +-
 .../authentication/token/JWTTokenStore.java        |  53 +---------
 .../{JWTTokenStore.java => JWTTokenStoreImpl.java} |  22 ++---
 .../authentication/token/OpenIDToken.java          | 108 +++++++++++++++++++++
 .../{TokenStore.java => OpenIDTokenStore.java}     |  13 ++-
 ...tSessionIDTokenStore.java => SessionToken.java} |   2 +-
 .../{SessionIDToken.java => SessionTokenImpl.java} |  15 +--
 .../{TokenStore.java => SessionTokenStore.java}    |  11 ++-
 .../servicecomb/authentication/token/Token.java    |   2 +-
 .../authentication/token/TokenStore.java           |   6 +-
 .../servicecomb/authentication/util/Constants.java |  27 ++++++
 .../authentication/edge/AuthHandler.java           |  41 +++++---
 .../authentication/edge/AuthenticationFilter.java  |   6 +-
 .../edge/DumyEdgeTokenResponseProcessor.java}      |  12 ++-
 ...yEdgeTokenStore.java => EdgeConfiguration.java} |  26 ++---
 ...nStore.java => EdgeTokenResponseProcessor.java} |   6 +-
 .../authentication/edge/TokenEndpoint.java         |   8 +-
 .../resource/ResourceAuthHandler.java              |  18 ++--
 docs/authentication.png                            | Bin 0 -> 85676 bytes
 docs/authorization.png                             | Bin 0 -> 79697 bytes
 docs/zh_CN/developersGuide.md                      |  83 +++++++---------
 .../AuthenticationConfiguration.java               |  32 +++---
 samples/Client/pom.xml                             |   9 --
 .../authentication/AuthenticationTestCase.java     |  29 +++---
 .../servicecomb/authentication/TestEndpoint.java   |  14 ++-
 .../apache/servicecomb/authentication/TestMgr.java |   4 +-
 .../gateway/AuthenticationConfiguration.java       |  25 ++++-
 .../resource/AuthenticationConfiguration.java      |  14 +--
 38 files changed, 523 insertions(+), 435 deletions(-)
 copy samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java => api/common/endpoint/src/main/java/org/apache/servicecomb/authentication/token/TokenConfiguration.java (55%)
 create mode 100644 api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractOpenIDTokenStore.java
 create mode 100644 api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemoryOpenIDTokenStore.java
 delete mode 100644 api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemorySessionIDTokenStore.java
 copy api/common/service/src/main/java/org/apache/servicecomb/authentication/token/{JWTToken.java => JWTTokenImpl.java} (93%)
 copy api/common/service/src/main/java/org/apache/servicecomb/authentication/token/{JWTTokenStore.java => JWTTokenStoreImpl.java} (78%)
 create mode 100644 api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDToken.java
 copy api/common/service/src/main/java/org/apache/servicecomb/authentication/token/{TokenStore.java => OpenIDTokenStore.java} (71%)
 rename api/common/service/src/main/java/org/apache/servicecomb/authentication/token/{AbstractSessionIDTokenStore.java => SessionToken.java} (92%)
 rename api/common/service/src/main/java/org/apache/servicecomb/authentication/token/{SessionIDToken.java => SessionTokenImpl.java} (87%)
 copy api/common/service/src/main/java/org/apache/servicecomb/authentication/token/{TokenStore.java => SessionTokenStore.java} (81%)
 copy api/edge-service/{service/src/main/java/org/apache/servicecomb/authentication/edge/TokenService.java => endpoint/src/main/java/org/apache/servicecomb/authentication/edge/DumyEdgeTokenResponseProcessor.java} (82%)
 rename api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/{InMemoryEdgeTokenStore.java => EdgeConfiguration.java} (62%)
 rename api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/{EdgeTokenStore.java => EdgeTokenResponseProcessor.java} (84%)
 create mode 100644 docs/authentication.png
 create mode 100644 docs/authorization.png


[servicecomb-fence] 04/09: [SCB-1293]1. add TokenStore to support stateless or stateful session management 2. refactor test cases and change developers guide

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit 1d2e250c22aa1f09f87cdbb0b1e22833c5b0bed7
Author: liubao <bi...@qq.com>
AuthorDate: Tue May 28 15:09:55 2019 +0800

    [SCB-1293]1. add TokenStore to support stateless or stateful session management 2. refactor test cases and change developers guide
---
 .../server/PasswordTokenGranter.java               |  51 ++++-----
 .../server/RefreshTokenTokenGranter.java           |  77 ++++++--------
 .../authentication/server/TokenEndpoint.java       |   6 +-
 .../authentication/server/TokenGranter.java        |   4 +-
 api/authentication-server/service/pom.xml          |   8 ++
 .../server/{Token.java => TokenResponse.java}      |  13 ++-
 .../authentication/server/TokenService.java        |   2 +-
 .../token/AbstractSessionIDTokenStore.java}        |   7 +-
 .../token/InMemorySessionIDTokenStore.java}        |  32 +++---
 .../servicecomb/authentication/token/JWTToken.java |  85 +++++++++++++++
 .../authentication/token/JWTTokenStore.java        |  71 +++++++++++++
 .../authentication/token/SessionIDToken.java       |  76 +++++++++++++
 .../servicecomb/authentication/token/Token.java}   |  18 +++-
 .../authentication/token/TokenStore.java}          |  10 +-
 .../servicecomb/authentication/util/Constants.java |   5 +-
 .../authentication/edge/AuthHandler.java           |  17 +--
 .../authentication/edge/AuthenticationFilter.java  |   0
 .../edge/AuthenticationServerTokenEndpoint.java}   |  27 ++---
 .../edge/CustomVertxRestDispatcher.java            |   1 +
 .../authentication/edge/EdgeTokenStore.java}       |  10 +-
 .../edge/InMemoryEdgeTokenStore.java}              |  28 +++--
 .../authentication/edge/InternalAccessHandler.java |   0
 .../authentication/edge/TokenEndpoint.java         |  65 ++++++++++++
 ...servicecomb.common.rest.filter.HttpServerFilter |   0
 ...cecomb.transport.rest.vertx.VertxHttpDispatcher |   2 +-
 .../src/main/resources/config/cse.handler.xml      |   0
 api/edge-service/service/pom.xml                   |   3 +-
 .../authentication/edge}/TokenService.java         |   8 +-
 .../resource/ResourceAuthHandler.java              |  24 ++---
 docs/zh_CN/developersGuide.md                      |  97 ++++++++++++-----
 .../AuthenticationConfiguration.java               |  30 ++++--
 .../authentication/AuthenticationTestCase.java     | 117 ++++++++-------------
 .../authentication/BootEventListener.java          |   7 +-
 .../authentication/GateRestTemplate.java           |   9 ++
 .../gateway/AuthenticationConfiguration.java       |  10 +-
 .../resource/AuthenticationConfiguration.java      |  19 +++-
 36 files changed, 652 insertions(+), 287 deletions(-)

diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
index 7d16268..a1538ff 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
@@ -18,18 +18,13 @@
 package org.apache.servicecomb.authentication.server;
 
 import java.util.Map;
-import java.util.UUID;
 
-import org.apache.servicecomb.authentication.jwt.JWTClaims;
-import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.apache.servicecomb.authentication.token.TokenStore;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.jwt.Jwt;
-import org.springframework.security.jwt.JwtHelper;
-import org.springframework.security.jwt.crypto.sign.Signer;
 import org.springframework.stereotype.Component;
 
 import com.netflix.config.DynamicPropertyFactory;
@@ -45,40 +40,34 @@ public class PasswordTokenGranter implements TokenGranter {
   private PasswordEncoder passwordEncoder;
 
   @Autowired
-  @Qualifier("authSigner")
-  private Signer signer;
+  @Qualifier("authAccessTokenStore")
+  private TokenStore accessTokenStore;
+
+  @Autowired
+  @Qualifier("authRefreshTokenStore")
+  private TokenStore refreshTokenStore;
+
+  @Autowired
+  @Qualifier("authIDTokenStore")
+  private TokenStore idTokenStore;
 
   @Override
-  public Token grant(Map<String, String> parameters) {
+  public TokenResponse grant(Map<String, String> parameters) {
     String username = parameters.get(TokenConst.PARAM_USERNAME);
     String password = parameters.get(TokenConst.PARAM_PASSWORD);
 
     UserDetails userDetails = userDetailsService.loadUserByUsername(username);
     if (passwordEncoder.matches(password, userDetails.getPassword())) {
-      JWTClaims claims = new JWTClaims();
-      if (userDetails.getAuthorities() != null) {
-        userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority()));
-      }
-      claims.setJti(UUID.randomUUID().toString());
-      claims.setIat(System.currentTimeMillis());
-      claims.setExp(5 * 60);
-      
-      String content = JsonParser.unparse(claims);
-      Jwt accessToken = JwtHelper.encode(content, signer);
-
-      Token token = new Token();
-      token.setScope(claims.getScope());
+      TokenResponse token = new TokenResponse();
+      token.setAccess_token(accessTokenStore.createToken(userDetails).getValue());
+      token.setRefresh_token(refreshTokenStore.createToken(userDetails).getValue());
+      token.setId_token(idTokenStore.createToken(userDetails).getValue());
+
+      //TODO add parameters.
+      token.setScope(null);
       token.setExpires_in(10 * 60);
       token.setToken_type("bearer");
-      token.setAccess_token(accessToken.getEncoded());
-      
-      JWTClaims accessTokenClaims = new JWTClaims();
-      accessTokenClaims.setJti(UUID.randomUUID().toString());
-      accessTokenClaims.setIat(System.currentTimeMillis());
-      accessTokenClaims.setExp(60 * 60);
-      Jwt refreshToken = JwtHelper.encode(JsonParser.unparse(claims), signer);
-      token.setRefresh_token(refreshToken.getEncoded());
-      
+
       return token;
     } else {
       return null;
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
index 7a41e90..6980287 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
@@ -19,14 +19,12 @@ package org.apache.servicecomb.authentication.server;
 
 import java.util.Map;
 
-import org.apache.servicecomb.authentication.jwt.JWTClaims;
-import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.apache.servicecomb.authentication.token.Token;
+import org.apache.servicecomb.authentication.token.TokenStore;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.security.jwt.Jwt;
-import org.springframework.security.jwt.JwtHelper;
-import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
-import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.stereotype.Component;
 
 import com.netflix.config.DynamicPropertyFactory;
@@ -34,12 +32,20 @@ import com.netflix.config.DynamicPropertyFactory;
 @Component(value = "fefreshTokenTokenGranter")
 public class RefreshTokenTokenGranter implements TokenGranter {
   @Autowired
-  @Qualifier("authSignatureVerifier")
-  private SignatureVerifier signerVerifier;
+  @Qualifier("authUserDetailsService")
+  private UserDetailsService userDetailsService;
 
   @Autowired
-  @Qualifier("authSigner")
-  private Signer signer;
+  @Qualifier("authAccessTokenStore")
+  private TokenStore accessTokenStore;
+
+  @Autowired
+  @Qualifier("authRefreshTokenStore")
+  private TokenStore refreshTokenStore;
+
+  @Autowired
+  @Qualifier("authIDTokenStore")
+  private TokenStore idTokenStore;
 
   @Override
   public boolean enabled() {
@@ -54,42 +60,27 @@ public class RefreshTokenTokenGranter implements TokenGranter {
   }
 
   @Override
-  public Token grant(Map<String, String> parameters) {
-    String refreshToken = parameters.get(TokenConst.PARAM_REFRESH_TOKEN);
-    String accessToken = parameters.get(TokenConst.PARAM_ACCESS_TOKEN);
-
-    // verify refresh tokens
-    Jwt jwt = JwtHelper.decode(refreshToken);
-    JWTClaims claims;
-    try {
-      jwt.verifySignature(signerVerifier);
-      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
-      // TODO: verify claims.
-    } catch (Exception e) {
-      return null;
-    }
+  public TokenResponse grant(Map<String, String> parameters) {
+    String refreshTokenValue = parameters.get(TokenConst.PARAM_REFRESH_TOKEN);
 
-    // verify access tokens
-    jwt = JwtHelper.decode(accessToken);
-    claims = null;
-    try {
-      jwt.verifySignature(signerVerifier);
-      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
-      // TODO: verify claims.
-    } catch (Exception e) {
-      return null;
-    }
+    Token refreshToken = refreshTokenStore.readTokenByValue(refreshTokenValue);
 
-    claims.setIat(System.currentTimeMillis());
-    String content = JsonParser.unparse(claims);
-    Jwt newAccessToken = JwtHelper.encode(content, signer);
+    if (refreshToken != null && !refreshToken.isExpired()) {
+      UserDetails userDetails = userDetailsService.loadUserByUsername(refreshToken.username());
 
-    Token token = new Token();
-    token.setScope(claims.getScope());
-    token.setExpires_in(10 * 60);
-    token.setToken_type("bearer");
-    token.setAccess_token(newAccessToken.getEncoded());
-    return token;
+      TokenResponse token = new TokenResponse();
+      token.setAccess_token(accessTokenStore.createToken(userDetails).getValue());
+      // refresh token is not generated 
+      token.setRefresh_token(refreshTokenValue);
+      token.setId_token(idTokenStore.createToken(userDetails).getValue());
+
+      //TODO add parameters.
+      token.setScope(null);
+      token.setExpires_in(10 * 60);
+      token.setToken_type("bearer");
+      return token;
+    }
+    return null;
   }
 
 }
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java
index 775d332..fa2ca32 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java
@@ -29,19 +29,19 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 @RestSchema(schemaId = "TokenEndpoint")
-@RequestMapping(path = "/v1/oauth/token")
+@RequestMapping(path = "/v1/token")
 public class TokenEndpoint implements TokenService {
   @Autowired
   private List<TokenGranter> granters;
 
   @Override
   @PostMapping(path = "/", consumes = MediaType.APPLICATION_FORM_URLENCODED)
-  public Token getAccessToken(@RequestBody Map<String, String> parameters) {
+  public TokenResponse getToken(@RequestBody Map<String, String> parameters) {
     String grantType = parameters.get(TokenConst.PARAM_GRANT_TYPE);
 
     for (TokenGranter granter : granters) {
       if (granter.enabled()) {
-        Token token = granter.grant(grantType, parameters);
+        TokenResponse token = granter.grant(grantType, parameters);
         if (token != null) {
           return token;
         }
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
index 9ba0861..e5f600b 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
@@ -29,12 +29,12 @@ public interface TokenGranter {
 
   String grantType();
 
-  default Token grant(String grantType, Map<String, String> parameters) {
+  default TokenResponse grant(String grantType, Map<String, String> parameters) {
     if (grantType().equals(grantType)) {
       return grant(parameters);
     }
     return null;
   }
 
-  Token grant(Map<String, String> parameters);
+  TokenResponse grant(Map<String, String> parameters);
 }
diff --git a/api/authentication-server/service/pom.xml b/api/authentication-server/service/pom.xml
index 4433ff6..8f9b5e2 100644
--- a/api/authentication-server/service/pom.xml
+++ b/api/authentication-server/service/pom.xml
@@ -28,4 +28,12 @@
   <artifactId>authentication-server-api-service</artifactId>
   <packaging>jar</packaging>
 
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-common-api-service</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+  </dependencies>
+
 </project>
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenResponse.java
similarity index 88%
rename from api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java
rename to api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenResponse.java
index 8758bd1..9bdc6d7 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java
+++ b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenResponse.java
@@ -20,7 +20,7 @@ package org.apache.servicecomb.authentication.server;
 import java.util.Map;
 import java.util.Set;
 
-public class Token {
+public class TokenResponse {
   // Naming conventions https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-00#section-3.1
   private String token_type;
 
@@ -28,6 +28,9 @@ public class Token {
 
   private String refresh_token;
 
+  // Naming conventions https://openid.net/specs/openid-connect-basic-1_0.html#ObtainingTokens
+  private String id_token;
+
   private int expires_in;
 
   private Set<String> scope;
@@ -69,6 +72,14 @@ public class Token {
     this.expires_in = expires_in;
   }
 
+  public String getId_token() {
+    return id_token;
+  }
+
+  public void setId_token(String id_token) {
+    this.id_token = id_token;
+  }
+
   public Set<String> getScope() {
     return scope;
   }
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
index b0cea22..8dbd197 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
+++ b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
@@ -20,5 +20,5 @@ package org.apache.servicecomb.authentication.server;
 import java.util.Map;
 
 public interface TokenService {
-  Token getAccessToken(Map<String, String> parameters);
+  TokenResponse getToken(Map<String, String> parameters);
 }
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractSessionIDTokenStore.java
similarity index 83%
copy from api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
copy to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractSessionIDTokenStore.java
index b0cea22..cb507a3 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractSessionIDTokenStore.java
@@ -15,10 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.server;
+package org.apache.servicecomb.authentication.token;
 
-import java.util.Map;
-
-public interface TokenService {
-  Token getAccessToken(Map<String, String> parameters);
+public abstract class AbstractSessionIDTokenStore implements TokenStore {
 }
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemorySessionIDTokenStore.java
similarity index 55%
copy from api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
copy to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemorySessionIDTokenStore.java
index 9ba0861..5bac8f0 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemorySessionIDTokenStore.java
@@ -15,26 +15,28 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.server;
+package org.apache.servicecomb.authentication.token;
 
+import java.util.HashMap;
 import java.util.Map;
 
-/**
- * Token granter is used to grant access tokens. 
- * @author Administrator
- *
- */
-public interface TokenGranter {
-  boolean enabled();
+import org.springframework.security.core.userdetails.UserDetails;
 
-  String grantType();
+public class InMemorySessionIDTokenStore extends AbstractSessionIDTokenStore {
+  private Map<String, SessionIDToken> tokens = new HashMap<>();
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public <T extends Token> T createToken(UserDetails userDetails) {
+    SessionIDToken token = new SessionIDToken(userDetails.getUsername());
+    tokens.put(token.getValue(), token);
+    return (T) token;
+  }
 
-  default Token grant(String grantType, Map<String, String> parameters) {
-    if (grantType().equals(grantType)) {
-      return grant(parameters);
-    }
-    return null;
+  @SuppressWarnings("unchecked")
+  @Override
+  public <T extends Token> T readTokenByValue(String value) {
+    return (T) tokens.get(value);
   }
 
-  Token grant(Map<String, String> parameters);
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java
new file mode 100644
index 0000000..e989ae5
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.token;
+
+import java.util.Map;
+
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.springframework.security.jwt.Jwt;
+import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.Signer;
+
+public class JWTToken implements Token {
+  private JWTClaims claims;
+
+  private boolean valueCalculated = false;
+
+  private String value;
+
+  private Signer signer;
+
+  public JWTToken(JWTClaims claims, Signer signer) {
+    this.claims = claims;
+    this.signer = signer;
+  }
+
+  @Override
+  public boolean isExpired() {
+    return System.currentTimeMillis() - this.getIssueAt() > this.getExpiration() * 1000;
+  }
+
+  @Override
+  public long getIssueAt() {
+    return this.claims.getIat();
+  }
+
+  @Override
+  public long getExpiration() {
+    return this.claims.getExp();
+  }
+
+  @Override
+  public long getNotBefore() {
+    return this.claims.getNbf();
+  }
+
+  @Override
+  public String getValue() {
+    if (!this.valueCalculated) {
+      String content = JsonParser.unparse(claims);
+      Jwt jwtToken = JwtHelper.encode(content, signer);
+      this.value = jwtToken.getEncoded();
+    }
+    return this.value;
+  }
+
+  @Override
+  public Map<String, Object> getAdditionalInformation() {
+    return this.claims.getAdditionalInformation();
+  }
+
+  @Override
+  public String username() {
+    return this.claims.getSub();
+  }
+  
+  public JWTClaims getClaims() {
+    return this.claims;
+  }
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java
new file mode 100644
index 0000000..2f394e7
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.token;
+
+import java.util.UUID;
+
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.jwt.Jwt;
+import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
+import org.springframework.security.jwt.crypto.sign.Signer;
+
+public class JWTTokenStore implements TokenStore {
+  private Signer signer;
+
+  private SignatureVerifier signerVerifier;
+
+  public JWTTokenStore(Signer signer, SignatureVerifier signerVerifier) {
+    this.signer = signer;
+    this.signerVerifier = signerVerifier;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public <T extends Token> T createToken(UserDetails userDetails) {
+    JWTClaims claims = new JWTClaims();
+    claims.setSub(userDetails.getUsername());
+    if (userDetails.getAuthorities() != null) {
+      userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority()));
+    }
+
+    // TODO : set other parameters.
+    claims.setJti(UUID.randomUUID().toString());
+    claims.setIat(System.currentTimeMillis());
+    claims.setExp(5 * 60);
+
+    return (T) new JWTToken(claims, signer);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public <T extends Token> T readTokenByValue(String value) {
+    Jwt jwt = JwtHelper.decode(value);
+    JWTClaims claims;
+    try {
+      jwt.verifySignature(signerVerifier);
+      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
+    } catch (Exception e) {
+      return null;
+    }
+    return (T) new JWTToken(claims, signer);
+  }
+
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionIDToken.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionIDToken.java
new file mode 100644
index 0000000..06a6f96
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionIDToken.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.token;
+
+import java.util.Map;
+import java.util.UUID;
+
+public class SessionIDToken implements Token {
+  private String value;
+
+  private long issueAt;
+
+  // in seconds
+  private long expiration;
+
+  private String username;
+
+  public SessionIDToken(String username) {
+    this.value = UUID.randomUUID().toString();
+    this.issueAt = System.currentTimeMillis();
+    // TODO add a configuration
+    this.expiration = 600;
+    this.username = username;
+  }
+
+  @Override
+  public boolean isExpired() {
+    return System.currentTimeMillis() - this.issueAt > this.expiration * 1000;
+  }
+
+  @Override
+  public long getIssueAt() {
+    return this.issueAt;
+  }
+
+  @Override
+  public long getExpiration() {
+    return this.expiration;
+  }
+
+  @Override
+  public long getNotBefore() {
+    // TODO add a configuration
+    return 0;
+  }
+
+  @Override
+  public String getValue() {
+    return this.value;
+  }
+
+  @Override
+  public Map<String, Object> getAdditionalInformation() {
+    // TODO add a configuration
+    return null;
+  }
+
+  public String username() {
+    return this.username;
+  }
+}
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
similarity index 75%
copy from api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
copy to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
index b0cea22..21b06d5 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
@@ -15,10 +15,22 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.server;
+package org.apache.servicecomb.authentication.token;
 
 import java.util.Map;
 
-public interface TokenService {
-  Token getAccessToken(Map<String, String> parameters);
+public interface Token {
+  String username();
+
+  boolean isExpired();
+
+  long getIssueAt();
+
+  long getExpiration();
+
+  long getNotBefore();
+
+  String getValue();
+
+  Map<String, Object> getAdditionalInformation();
 }
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java
similarity index 75%
copy from api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
copy to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java
index b0cea22..1f26610 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java
@@ -15,10 +15,12 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.server;
+package org.apache.servicecomb.authentication.token;
 
-import java.util.Map;
+import org.springframework.security.core.userdetails.UserDetails;
 
-public interface TokenService {
-  Token getAccessToken(Map<String, String> parameters);
+public interface TokenStore {
+  <T extends Token> T createToken(UserDetails userDetails);
+  
+  <T extends Token> T readTokenByValue(String value);
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java
index 96333aa..4dcc8e7 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java
@@ -21,6 +21,9 @@ public final class Constants {
   public static final String HTTP_HEADER_AUTHORIZATION = "Authorization";
 
   public static final String CONTEXT_HEADER_AUTHORIZATION = "Authorization";
-  
+
   public static final String CONTEXT_HEADER_CLAIMS = "Claims";
+
+  public static final String TOKEN_TYPE_BEARER = "Bearer";
+
 }
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
similarity index 78%
rename from api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
rename to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
index abf4587..d209be4 100644
--- a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
@@ -17,32 +17,35 @@
 
 package org.apache.servicecomb.authentication.edge;
 
+import org.apache.servicecomb.authentication.server.TokenResponse;
 import org.apache.servicecomb.authentication.util.Constants;
 import org.apache.servicecomb.core.Handler;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.swagger.invocation.AsyncResponse;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
-import org.springframework.security.jwt.Jwt;
-import org.springframework.security.jwt.JwtHelper;
-import org.springframework.security.jwt.crypto.sign.InvalidSignatureException;
 
 
 public class AuthHandler implements Handler {
   @Override
   public void handle(Invocation invocation, AsyncResponse asyncResponse) throws Exception {
+    EdgeTokenStore edgeTokenStore = BeanUtils.getBean("authEdgeTokenStore");
+
     String token = invocation.getContext(Constants.CONTEXT_HEADER_AUTHORIZATION);
     if (token == null) {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
     }
-    Jwt jwt = JwtHelper.decode(token);
-    try {
-      jwt.verifySignature(BeanUtils.getBean("authSignatureVerifier"));
-    } catch (InvalidSignatureException e) {
+
+    TokenResponse tokenResonse = edgeTokenStore.readTokenResponse(token);
+    if (tokenResonse == null) {
+      // TODO : check token validity by expiration time
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
     }
+
+    // send id_token to services to apply state less validation
+    invocation.addContext(Constants.CONTEXT_HEADER_AUTHORIZATION, tokenResonse.getId_token());
     invocation.next(asyncResponse);
   }
 }
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java
similarity index 100%
rename from api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java
rename to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationServerTokenEndpoint.java
similarity index 59%
copy from api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
copy to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationServerTokenEndpoint.java
index 9ba0861..50c29d3 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationServerTokenEndpoint.java
@@ -15,26 +15,17 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.server;
+package org.apache.servicecomb.authentication.edge;
 
 import java.util.Map;
+import java.util.concurrent.CompletableFuture;
 
-/**
- * Token granter is used to grant access tokens. 
- * @author Administrator
- *
- */
-public interface TokenGranter {
-  boolean enabled();
-
-  String grantType();
-
-  default Token grant(String grantType, Map<String, String> parameters) {
-    if (grantType().equals(grantType)) {
-      return grant(parameters);
-    }
-    return null;
-  }
+import org.apache.servicecomb.authentication.server.TokenResponse;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 
-  Token grant(Map<String, String> parameters);
+public interface AuthenticationServerTokenEndpoint {
+  @PostMapping(path = "/", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+  public CompletableFuture<TokenResponse> getToken(@RequestBody Map<String, String> parameters);
 }
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java
similarity index 99%
rename from api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java
rename to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java
index 521b71c..a08873d 100644
--- a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java
@@ -63,6 +63,7 @@ public class CustomVertxRestDispatcher extends AbstractVertxHttpDispatcher {
 
   @Override
   public void init(Router router) {
+    // TODO: regex configuration
     String regex = "(/v1/log|/inspector|/v1/auth)/(.*)";
     router.routeWithRegex(regex).handler(CookieHandler.create());
     router.routeWithRegex(regex).handler(createBodyHandler());
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java
similarity index 73%
copy from api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
copy to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java
index b0cea22..92bbbaf 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java
@@ -15,10 +15,12 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.server;
+package org.apache.servicecomb.authentication.edge;
 
-import java.util.Map;
+import org.apache.servicecomb.authentication.server.TokenResponse;
 
-public interface TokenService {
-  Token getAccessToken(Map<String, String> parameters);
+public interface EdgeTokenStore {
+  TokenResponse readTokenResponse(String accessTokenValue);
+
+  void saveTokenResponse(String accessTokenValue, TokenResponse tokenResponse);
 }
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/InMemoryEdgeTokenStore.java
similarity index 60%
copy from api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
copy to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/InMemoryEdgeTokenStore.java
index 9ba0861..03a7baa 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/InMemoryEdgeTokenStore.java
@@ -15,26 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.server;
+package org.apache.servicecomb.authentication.edge;
 
+import java.util.HashMap;
 import java.util.Map;
 
-/**
- * Token granter is used to grant access tokens. 
- * @author Administrator
- *
- */
-public interface TokenGranter {
-  boolean enabled();
+import org.apache.servicecomb.authentication.server.TokenResponse;
 
-  String grantType();
+public class InMemoryEdgeTokenStore implements EdgeTokenStore {
+  private Map<String, TokenResponse> tokens = new HashMap<>();
+
+  @Override
+  public TokenResponse readTokenResponse(String accessTokenValue) {
+    return tokens.get(accessTokenValue);
+  }
 
-  default Token grant(String grantType, Map<String, String> parameters) {
-    if (grantType().equals(grantType)) {
-      return grant(parameters);
-    }
-    return null;
+  @Override
+  public void saveTokenResponse(String accessTokenValue, TokenResponse tokenResponse) {
+    tokens.put(accessTokenValue, tokenResponse);
   }
 
-  Token grant(Map<String, String> parameters);
 }
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/InternalAccessHandler.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/InternalAccessHandler.java
similarity index 100%
rename from api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/InternalAccessHandler.java
rename to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/InternalAccessHandler.java
diff --git a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/TokenEndpoint.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/TokenEndpoint.java
new file mode 100644
index 0000000..87dcbb0
--- /dev/null
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/TokenEndpoint.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.edge;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import org.apache.servicecomb.authentication.server.TokenResponse;
+import org.apache.servicecomb.provider.pojo.RpcReference;
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@RestSchema(schemaId = "TokenEndpoint")
+@RequestMapping(path = "/v1/token")
+public class TokenEndpoint implements TokenService {
+  @RpcReference(microserviceName = "authentication-server", schemaId = "TokenEndpoint")
+  private AuthenticationServerTokenEndpoint authenticationSererTokenEndpoint;
+
+  @Autowired
+  @Qualifier("authEdgeTokenStore")
+  private EdgeTokenStore edgeTokenStore;
+
+
+  @Override
+  @PostMapping(path = "/", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+  public CompletableFuture<TokenResponse> getToken(@RequestBody Map<String, String> parameters) {
+    CompletableFuture<TokenResponse> result = new CompletableFuture<>();
+
+    HttpHeaders headers = new HttpHeaders();
+    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+
+    CompletableFuture<TokenResponse> response =
+        authenticationSererTokenEndpoint.getToken(parameters);
+    response.whenComplete((tokenResonse, ex) -> {
+      if (!response.isCompletedExceptionally()) {
+        result.complete(tokenResonse);
+        edgeTokenStore.saveTokenResponse(tokenResonse.getAccess_token(), tokenResonse);
+      } else {
+        result.completeExceptionally(ex);
+      }
+    });
+    return result;
+  }
+}
diff --git a/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter b/api/edge-service/endpoint/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter
similarity index 100%
rename from api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter
rename to api/edge-service/endpoint/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter
diff --git a/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher b/api/edge-service/endpoint/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
similarity index 91%
rename from api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
rename to api/edge-service/endpoint/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
index 32c1583..53481f1 100644
--- a/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
+++ b/api/edge-service/endpoint/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
@@ -15,4 +15,4 @@
 # limitations under the License.
 #
 
-# org.apache.servicecomb.authentication.edge.CustomVertxRestDispatcher
\ No newline at end of file
+org.apache.servicecomb.authentication.edge.CustomVertxRestDispatcher
\ No newline at end of file
diff --git a/api/edge-service/service/src/main/resources/config/cse.handler.xml b/api/edge-service/endpoint/src/main/resources/config/cse.handler.xml
similarity index 100%
rename from api/edge-service/service/src/main/resources/config/cse.handler.xml
rename to api/edge-service/endpoint/src/main/resources/config/cse.handler.xml
diff --git a/api/edge-service/service/pom.xml b/api/edge-service/service/pom.xml
index 8d86c00..487f146 100644
--- a/api/edge-service/service/pom.xml
+++ b/api/edge-service/service/pom.xml
@@ -36,7 +36,8 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.servicecomb.authentication</groupId>
-      <artifactId>authentication-common-api-endpoint</artifactId>
+      <artifactId>authentication-server-api-service</artifactId>
+      <version>${project.parent.version}</version>
     </dependency>
   </dependencies>
 </project>
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/TokenService.java
similarity index 77%
copy from api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
copy to api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/TokenService.java
index b0cea22..5e12a45 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
+++ b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/TokenService.java
@@ -15,10 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.server;
+package org.apache.servicecomb.authentication.edge;
 
 import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import org.apache.servicecomb.authentication.server.TokenResponse;
+
 
 public interface TokenService {
-  Token getAccessToken(Map<String, String> parameters);
+  CompletableFuture<TokenResponse> getToken(Map<String, String> parameters);
 }
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
index 68c6960..5c81139 100644
--- a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
@@ -21,8 +21,8 @@ import java.util.HashSet;
 import java.util.Set;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.servicecomb.authentication.jwt.JWTClaims;
-import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.apache.servicecomb.authentication.token.JWTToken;
+import org.apache.servicecomb.authentication.token.JWTTokenStore;
 import org.apache.servicecomb.authentication.util.Constants;
 import org.apache.servicecomb.core.Handler;
 import org.apache.servicecomb.core.Invocation;
@@ -35,8 +35,6 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.context.SecurityContextImpl;
-import org.springframework.security.jwt.Jwt;
-import org.springframework.security.jwt.JwtHelper;
 
 public class ResourceAuthHandler implements Handler {
 
@@ -56,23 +54,19 @@ public class ResourceAuthHandler implements Handler {
       return;
     }
     // verify tokens
-    Jwt jwt = JwtHelper.decode(token);
-    JWTClaims claims;
-    try {
-      jwt.verifySignature(BeanUtils.getBean("authSignatureVerifier"));
-      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
-      // TODO: verify claims.
-    } catch (Exception e) {
+    JWTTokenStore store = BeanUtils.getBean("authIDTokenStore");
+    JWTToken t = store.readTokenByValue(token);
+    if(t == null) {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
     }
-
+    
     // check roles
     if (!StringUtils.isEmpty(config.roles)) {
       String[] roles = config.roles.split(",");
       if (roles.length > 0) {
         boolean valid = false;
-        Set<String> authorities = claims.getAuthorities();
+        Set<String> authorities = t.getClaims().getAuthorities();
         for (String role : roles) {
           if (authorities.contains(role)) {
             valid = true;
@@ -87,8 +81,8 @@ public class ResourceAuthHandler implements Handler {
     }
 
     // pre method authentiation
-    Set<GrantedAuthority> grantedAuthorities = new HashSet<>(claims.getAuthorities().size());
-    claims.getAuthorities().forEach(v -> grantedAuthorities.add(new SimpleGrantedAuthority(v)));
+    Set<GrantedAuthority> grantedAuthorities = new HashSet<>(t.getClaims().getAuthorities().size());
+    t.getClaims().getAuthorities().forEach(v -> grantedAuthorities.add(new SimpleGrantedAuthority(v)));
     SecurityContext sc = new SecurityContextImpl();
     Authentication authentication = new SimpleAuthentication(true, grantedAuthorities);
     sc.setAuthentication(authentication);
diff --git a/docs/zh_CN/developersGuide.md b/docs/zh_CN/developersGuide.md
index 013f98f..3d67833 100644
--- a/docs/zh_CN/developersGuide.md
+++ b/docs/zh_CN/developersGuide.md
@@ -11,15 +11,37 @@
 ```
 ** HTTP Request **
 
-POST http://localhost:9090/api/authentication-server/v1/oauth/token HTTP/1.1
+POST http://localhost:9090/v1/token HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
 
 grant_type=password&username=admin&password=changeMyPassword
+
+** HTTP Response **
+
+{
+    "token_type": "bearer",
+    "access_token": "SlAV32hkKG",
+    "refresh_token": "8xLOxBtZp8",
+    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
+     yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
+     NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
+     fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
+     AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
+     Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
+     NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
+     QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
+     K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
+     XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg",
+    "expires_in": 600,
+    "scope": null,
+    "jti": null,
+    "additionalInformation": null
+}
 ```
 
   * Authentication Server 发送 Token 给 Client 。
 
-  * Client 携带 Token 请求 Resource Server 。
+  * Client 携带  Access Token 请求 Edge Service 。
 
 ```
 ** HTTP Request **
@@ -29,6 +51,7 @@ Content-Type: application/x-www-form-urlencoded
 Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW
 ```
 
+  * Edge Service 将 Access Token 转换为对应的 ID Token , 然后将请求转发给Resource Server。
   * Resource Server 返回对应的资源给 Client 。 
 
 ## 开发 Authentication Server
@@ -48,31 +71,38 @@ Authentication Server 主要提供认证和授权等接口。
 
 * 配置
 
-Authentication Server 需要配置 PasswordEncoder、Signer、SignerVerifier、UserDetailsService 等。这些对象和 Spring Security的概念一样。
+Authentication Server 需要配置 PasswordEncoder、Signer、SignerVerifier、TokenStore、UserDetailsService 等。
 ```
 @Configuration
 public class AuthenticationConfiguration {
-  @Autowired
-  @Qualifier("authPasswordEncoder")
-  private PasswordEncoder passwordEncoder;
-
   @Bean(name = "authPasswordEncoder")
   public PasswordEncoder authPasswordEncoder() {
     return new Pbkdf2PasswordEncoder();
   }
 
-  @Bean(name = "authSigner")
-  public Signer authSigner() {
-    return authSignerVerifier();
-  }
-  
-  @Bean(name = "authSignerVerifier")
+  @Bean(name = {"authSigner", "authSignatureVerifier"})
   public SignerVerifier authSignerVerifier() {
+    // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
+    // If using MacSigner, need to protect the shared key by properly encryption.
     return new MacSigner("Please change this key.");
   }
 
+  @Bean(name = {"authAccessTokenStore", "authRefreshTokenStore"})
+  public TokenStore sessionIDTokenStore() {
+    // Use in memory store for testing. Need to implement JDBC or Redis SessionIDTokenStore in product. 
+    return new InMemorySessionIDTokenStore();
+  }
+
+  @Bean(name = "authIDTokenStore")
+  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
+      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
+    return new JWTTokenStore(signer, signerVerifier);
+  }
+
   @Bean(name = "authUserDetailsService")
-  public UserDetailsService authUserDetailsService() {
+  public UserDetailsService authUserDetailsService(
+      @Autowired @Qualifier("authPasswordEncoder") PasswordEncoder passwordEncoder) {
+    // Use in memory UserDetails, need to implement JDBC or others in product
     InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
     UserDetails uAdmin = new User("admin", passwordEncoder.encode("changeMyPassword"),
         Arrays.asList(new SimpleGrantedAuthority("ADMIN")));
@@ -93,6 +123,9 @@ public class AuthenticationConfiguration {
 
 生成 Token 和对 Token 进行校验。Singer 和  SignatureVerifier 是配套使用的, 在 Authentication Server , 生成 Token 的时候,需要使用 Singer 。 验证 Token 的有效性 (比如查询 userDetails 等场景), 需要使用  SignatureVerifier 。 通常有两种方式进行签名和校验, 一种是基于对称秘钥的机制,比如MacSigner,即是 Singer, 也是 SignatureVerifier (SignerVerifier); 一种是基于非对称秘钥的机制, 比如 RsaSigner 和  RsaVerifier , 生成 Token 和校验 Token 的秘钥是不同的。
 
+* TokenStore
+在Authentication Server,TokenStore主要用来生成Access Token, Refresh Token和ID Token, 默认情况下, Access Token和Refresh Token都使用AbstractSessionIDTokenStore(本例子使用了InMemorySessionIDTokenStore,业务代码通常需要换为JDBC、Redis等实现), ID Token使用JWTTokenStore。 JWTTokenStore是一个无状态的会话机制,Authentication Server的任何一个实例都可以独立生成。
+
 * PasswordEncoder 
 
 从 UserDetailsService 校验用户密码的时候需要使用。 开发者需要在加密性能和保密程度方面选择合适的算法。 常用的有 Pbkdf2PasswordEncoder , 它可以设置迭代次数,能够更好的保护密码不被暴力破解。 
@@ -114,17 +147,30 @@ Resource Server 对 Client 的访问进行认证, 并进行权限控制。
 
 * 配置
 
-Resource Server 需要配置 SignatureVerifier 等, 对用户会话进行认证。 
+Resource Server 需要配置 Signer、SignatureVerifier、TokenStore 等, 对用户会话进行认证。 
+
 ```
-@Configuration
-public class AuthenticationConfiguration {
-  @Bean(name = "authSignatureVerifier")
-  public SignerVerifier authSignatureVerifier() {
+  @Bean(name = {"authSigner", "authSignatureVerifier"})
+  public SignerVerifier authSignerVerifier() {
+    // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
+    // If using MacSigner, need to protect the shared key by properly encryption.
     return new MacSigner("Please change this key.");
   }
-}
+
+  @Bean(name = "authIDTokenStore")
+  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
+      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
+    return new JWTTokenStore(signer, signerVerifier);
+  }
 ```
 
+* Signer、SignatureVerifier
+对Token进行校验需要,实际上Resource Server只需要使用SignatureVerifier。
+
+* TokenStore
+默认情况下, Edge Service将ID Token传递给Resource Server,所以只需要配置authIDTokenStore。
+
+
 * 权限配置
 
 fence 提供了两种方式进行权限配置。 一种是基于配置文件的,一种是基于 Annotation 。
@@ -205,15 +251,14 @@ Edge Service 是微服务接入层。 在[单体应用微服务改造](https://b
 
 * 配置
 
-Edge Service 需要配置 SignatureVerifier 等, 对用户会话进行认证。 
-```
+Edge Service 需要配置 EdgeTokenStore 等, 对用户会话进行认证。Edge Service 从HTTP头里面读取Access Token, 然后通过 EdgeTokenStore比对是否Access Token有效,如果有效,将对应的 ID Token传递到 Resource Server。 这里使用了 InMemoryEdgeTokenStore, 产品代码会多实例部署 Edge Service, 需要将其替换为 JDBC 或者 Redis 等实现。 
 
+```
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSignatureVerifier")
-  public SignerVerifier authSignatureVerifier() {
-    return new MacSigner("Please change this key.");
+  @Bean(name = "authEdgeTokenStore")
+  public EdgeTokenStore authEdgeTokenStore() {
+    return new InMemoryEdgeTokenStore();
   }
 }
-
 ```
diff --git a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
index b70273f..20e9f68 100644
--- a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
+++ b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
@@ -19,6 +19,9 @@ package org.apache.servicecomb.authentication;
 
 import java.util.Arrays;
 
+import org.apache.servicecomb.authentication.token.InMemorySessionIDTokenStore;
+import org.apache.servicecomb.authentication.token.JWTTokenStore;
+import org.apache.servicecomb.authentication.token.TokenStore;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Bean;
@@ -30,28 +33,41 @@ import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
+import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
+import org.springframework.security.jwt.crypto.sign.Signer;
 import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Autowired
-  @Qualifier("authPasswordEncoder")
-  private PasswordEncoder passwordEncoder;
-
   @Bean(name = "authPasswordEncoder")
   public PasswordEncoder authPasswordEncoder() {
     return new Pbkdf2PasswordEncoder();
   }
 
-  // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
-  @Bean(name = {"authSigner", "authSignatureVerifier" })
+  @Bean(name = {"authSigner", "authSignatureVerifier"})
   public SignerVerifier authSignerVerifier() {
+    // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
+    // If using MacSigner, need to protect the shared key by properly encryption.
     return new MacSigner("Please change this key.");
   }
 
+  @Bean(name = {"authAccessTokenStore", "authRefreshTokenStore"})
+  public TokenStore sessionIDTokenStore() {
+    // Use in memory store for testing. Need to implement JDBC or Redis SessionIDTokenStore in product. 
+    return new InMemorySessionIDTokenStore();
+  }
+
+  @Bean(name = "authIDTokenStore")
+  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
+      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
+    return new JWTTokenStore(signer, signerVerifier);
+  }
+
   @Bean(name = "authUserDetailsService")
-  public UserDetailsService authUserDetailsService() {
+  public UserDetailsService authUserDetailsService(
+      @Autowired @Qualifier("authPasswordEncoder") PasswordEncoder passwordEncoder) {
+    // Use in memory UserDetails, need to implement JDBC or others in product
     InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
     UserDetails uAdmin = new User("admin", passwordEncoder.encode("changeMyPassword"),
         Arrays.asList(new SimpleGrantedAuthority("ADMIN")));
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
index 13bfaba..e05545f 100644
--- a/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
@@ -17,13 +17,10 @@
 
 package org.apache.servicecomb.authentication;
 
-import org.apache.servicecomb.authentication.jwt.JWTClaims;
-import org.apache.servicecomb.authentication.jwt.JsonParser;
-import org.apache.servicecomb.authentication.server.Token;
+import org.apache.servicecomb.authentication.server.TokenResponse;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
-import org.springframework.security.jwt.JwtHelper;
 import org.springframework.stereotype.Component;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
@@ -33,12 +30,16 @@ import org.springframework.web.client.HttpClientErrorException;
 public class AuthenticationTestCase implements TestCase {
   @Override
   public void run() {
-    testHanlderAuth();
-    testMethodAuth();
-  }
+    String accessToken = accessToken();
+    testHanlderAuth(accessToken);
+    testMethodAuth(accessToken);
 
+    accessToken = accessTokenByRefreshToken();
+    testHanlderAuth(accessToken);
+    testMethodAuth(accessToken);
+  }
 
-  private void testHanlderAuth() {
+  private String accessToken() {
     // get token
     MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
     map.add("grant_type", "password");
@@ -47,68 +48,55 @@ public class AuthenticationTestCase implements TestCase {
     HttpHeaders headers = new HttpHeaders();
     headers.setContentType(MediaType.MULTIPART_FORM_DATA);
 
-    Token token =
-        BootEventListener.authenticationServerTokenEndpoint.postForObject("/",
+    TokenResponse token =
+        BootEventListener.edgeServiceTokenEndpoint.postForObject("/",
             new HttpEntity<>(map, headers),
-            Token.class);
+            TokenResponse.class);
     TestMgr.check("bearer", token.getToken_type());
     TestMgr.check(true, token.getAccess_token().length() > 10);
+    return token.getAccess_token();
+  }
 
-    // get resources
-    headers = new HttpHeaders();
-    headers.add("Authorization", "Bearer " + token.getAccess_token());
-    headers.setContentType(MediaType.APPLICATION_JSON);
-    String name;
-    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/everyoneSayHello?name=Hi",
-        new HttpEntity<>(headers),
-        String.class);
-    TestMgr.check("Hi", name);
-
-    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/adminSayHello?name=Hi",
-        new HttpEntity<>(headers),
-        String.class);
-    TestMgr.check("Hi", name);
+  private String accessTokenByRefreshToken() {
+    // get token
+    MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
+    map.add("grant_type", "password");
+    map.add("username", "admin");
+    map.add("password", "changeMyPassword");
+    HttpHeaders headers = new HttpHeaders();
+    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
 
-    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/guestOrAdminSayHello?name=Hi",
-        new HttpEntity<>(headers),
-        String.class);
-    TestMgr.check("Hi", name);
+    TokenResponse token =
+        BootEventListener.edgeServiceTokenEndpoint.postForObject("/",
+            new HttpEntity<>(map, headers),
+            TokenResponse.class);
+    TestMgr.check("bearer", token.getToken_type());
+    TestMgr.check(true, token.getAccess_token().length() > 10);
 
-    name = null;
-    try {
-      name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/guestSayHello?name=Hi",
-          new HttpEntity<>(headers),
-          String.class);
-    } catch (HttpClientErrorException e) {
-      TestMgr.check(403, e.getStatusCode().value());
-    }
-    TestMgr.check(null, name);
-    
     // refresh token
-    // get token
     map = new LinkedMultiValueMap<>();
     map.add("grant_type", "refresh_token");
     map.add("refresh_token", token.getRefresh_token());
-    map.add("access_token", token.getAccess_token());
-    headers = new HttpHeaders();
-    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
 
-    Token tokenNew =
-        BootEventListener.authenticationServerTokenEndpoint.postForObject("/",
+    TokenResponse tokenNew =
+        BootEventListener.edgeServiceTokenEndpoint.postForObject("/",
             new HttpEntity<>(map, headers),
-            Token.class);
+            TokenResponse.class);
     TestMgr.check(token.getToken_type(), tokenNew.getToken_type());
-   
-    JWTClaims claims = JsonParser.parse(JwtHelper.decode(token.getAccess_token()).getClaims(), JWTClaims.class);
-    JWTClaims newClaims = JsonParser.parse(JwtHelper.decode(tokenNew.getAccess_token()).getClaims(), JWTClaims.class);
-    TestMgr.check(claims.getJti(), newClaims.getJti());
-    TestMgr.check(claims.getIat() < newClaims.getIat(), true);
+    TestMgr.check(token.getRefresh_token(), tokenNew.getRefresh_token());
+    TestMgr.check(token.getAccess_token().equals(tokenNew.getAccess_token()), false);
+    TestMgr.check(token.getId_token().equals(tokenNew.getId_token()), false);
+
+    return tokenNew.getAccess_token();
+  }
 
+  private void testHanlderAuth(String accessToken) {
     // get resources
+    HttpHeaders headers = new HttpHeaders();
     headers = new HttpHeaders();
-    headers.add("Authorization", "Bearer " + tokenNew.getAccess_token());
+    headers.add("Authorization", "Bearer " + accessToken);
     headers.setContentType(MediaType.APPLICATION_JSON);
-
+    String name;
     name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/everyoneSayHello?name=Hi",
         new HttpEntity<>(headers),
         String.class);
@@ -135,27 +123,10 @@ public class AuthenticationTestCase implements TestCase {
     TestMgr.check(null, name);
   }
 
-
-  private void testMethodAuth() {
-    // get token
-    MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
-    map.add("grant_type", "password");
-    map.add("username", "admin");
-    map.add("password", "changeMyPassword");
-    HttpHeaders headers = new HttpHeaders();
-    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
-
-    Token token =
-        BootEventListener.authenticationServerTokenEndpoint.postForObject("/",
-            new HttpEntity<>(map, headers),
-            Token.class);
-    TestMgr.check("bearer", token.getToken_type());
-    TestMgr.check(true, token.getAccess_token().length() > 10);
-    TestMgr.check(true, token.getRefresh_token().length() > 10);
-
+  private void testMethodAuth(String accessToken) {
     // get resources
-    headers = new HttpHeaders();
-    headers.add("Authorization", "Bearer " + token.getAccess_token());
+    HttpHeaders headers = new HttpHeaders();
+    headers.add("Authorization", "Bearer " + accessToken);
     headers.setContentType(MediaType.APPLICATION_JSON);
     String name;
     name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/everyoneSayHello?name=Hi",
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java
index 08d1bb3..74db45a 100644
--- a/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java
@@ -23,7 +23,8 @@ import org.springframework.stereotype.Component;
 @Component
 public class BootEventListener implements BootListener {
   public static GateRestTemplate authenticationServerTokenEndpoint;
-  public static GateRestTemplate gateEndpoint;
+  public static GateRestTemplate edgeService;
+  public static GateRestTemplate edgeServiceTokenEndpoint;
   public static GateRestTemplate resouceServerHandlerAuthEndpoint;
   public static GateRestTemplate resouceServerMethodAuthEndpoint;
   
@@ -32,8 +33,10 @@ public class BootEventListener implements BootListener {
     if (EventType.AFTER_REGISTRY.equals(event.getEventType())) {
       authenticationServerTokenEndpoint =
           GateRestTemplate.createEdgeRestTemplate("edge-service", "authentication-server", "TokenEndpoint").init();
-      gateEndpoint =
+      edgeService =
           GateRestTemplate.createEdgeRestTemplate("edge-service", null, null).init();
+      edgeServiceTokenEndpoint =
+          GateRestTemplate.createEdgeRestTemplate("edge-service", "edge-service", "TokenEndpoint").init();
       resouceServerHandlerAuthEndpoint =
           GateRestTemplate.createEdgeRestTemplate("edge-service", "resource-server", "HandlerAuthEndpoint").init();
       resouceServerMethodAuthEndpoint =
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/GateRestTemplate.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/GateRestTemplate.java
index 7a6709f..df981e5 100644
--- a/samples/Client/src/main/java/org/apache/servicecomb/authentication/GateRestTemplate.java
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/GateRestTemplate.java
@@ -100,6 +100,15 @@ public class GateRestTemplate extends RestTemplate {
             DefinitionConst.VERSION_RULE_ALL);
     MicroserviceVersionMeta microserviceVersionMeta = microserviceVersionRule.getLatestMicroserviceVersion();
     SchemaMeta schemaMeta = microserviceVersionMeta.getMicroserviceMeta().ensureFindSchemaMeta(schemaId);
+
+    if(producerName.equals(gateName)) {
+      return String
+          .format("%s://%s:%d/%s",
+              urlSchema,
+              edgeAddress.getHostOrIp(),
+              edgeAddress.getPort(),
+              schemaMeta.getSwagger().getBasePath());
+    }
     return String
         .format("%s://%s:%d/api/%s%s",
             urlSchema,
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
index 510d821..e9187b7 100644
--- a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
@@ -17,15 +17,15 @@
 
 package org.apache.servicecomb.authentication.gateway;
 
+import org.apache.servicecomb.authentication.edge.EdgeTokenStore;
+import org.apache.servicecomb.authentication.edge.InMemoryEdgeTokenStore;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSignatureVerifier")
-  public SignerVerifier authSignatureVerifier() {
-    return new MacSigner("Please change this key.");
+  @Bean(name = "authEdgeTokenStore")
+  public EdgeTokenStore authEdgeTokenStore() {
+    return new InMemoryEdgeTokenStore();
   }
 }
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
index 2074321..e69217f 100644
--- a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
@@ -17,15 +17,30 @@
 
 package org.apache.servicecomb.authentication.resource;
 
+import org.apache.servicecomb.authentication.token.JWTTokenStore;
+import org.apache.servicecomb.authentication.token.TokenStore;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
 import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
+import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSignatureVerifier")
-  public SignatureVerifier authSignatureVerifier() {
+  @Bean(name = {"authSigner", "authSignatureVerifier"})
+  public SignerVerifier authSignerVerifier() {
+    // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
+    // If using MacSigner, need to protect the shared key by properly encryption.
     return new MacSigner("Please change this key.");
   }
+
+  @Bean(name = "authIDTokenStore")
+  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
+      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
+    return new JWTTokenStore(signer, signerVerifier);
+  }
+
 }


[servicecomb-fence] 03/09: Merge pull request #1 from liubao68/master

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit b4451da42e27ec0cd426c20d8a956445eefbfd20
Merge: 7e4d7e4 46de410
Author: bao liu <bi...@qq.com>
AuthorDate: Mon May 27 09:39:55 2019 +0800

    Merge pull request #1 from liubao68/master
    
    [SCB-1292]Add developers guide for servicecomb-fence and fix authSignatureVerifier

 README.md                                          | 108 +++-------
 .../server/RefreshTokenTokenGranter.java           |   6 +-
 .../authentication/edge/AuthHandler.java           |   2 +-
 .../resource/ResourceAuthHandler.java              |   2 +-
 docs/en_US/developersGuide.md                      |   1 +
 docs/zh_CN/developersGuide.md                      | 219 +++++++++++++++++++++
 .../AuthenticationConfiguration.java               |   9 +-
 samples/EdgeService/pom.xml                        |   4 -
 .../gateway/AuthenticationConfiguration.java       |   4 +-
 .../resource/AuthenticationConfiguration.java      |   6 +-
 10 files changed, 258 insertions(+), 103 deletions(-)


[servicecomb-fence] 01/09: Initial commit

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit 7e4d7e4298078a7fc0eae88d7842483f8cdf10f9
Author: liubao <ba...@huawei.com>
AuthorDate: Fri May 24 14:43:59 2019 +0800

    Initial commit
---
 .gitignore                                         |  82 +++++++++
 README.md                                          | 110 ++++++++++++
 api/authentication-server/endpoint/pom.xml         |  43 +++++
 .../server/PasswordTokenGranter.java               | 100 +++++++++++
 .../server/RefreshTokenTokenGranter.java           |  95 ++++++++++
 .../authentication/server/TokenEndpoint.java       |  54 ++++++
 .../authentication/server/TokenGranter.java        |  40 +++++
 api/authentication-server/pom.xml                  |  36 ++++
 api/authentication-server/service/pom.xml          |  31 ++++
 .../servicecomb/authentication/server/Token.java   |  96 ++++++++++
 .../authentication/server/TokenConst.java          |  34 ++++
 .../authentication/server/TokenService.java        |  24 +++
 api/common/endpoint/pom.xml                        |  38 ++++
 api/common/pom.xml                                 |  36 ++++
 api/common/service/pom.xml                         |  56 ++++++
 .../servicecomb/authentication/jwt/JWTClaims.java  |  80 +++++++++
 .../authentication/jwt/JWTClaimsCommon.java        | 100 +++++++++++
 .../servicecomb/authentication/jwt/JWTHeader.java  |  42 +++++
 .../servicecomb/authentication/jwt/JsonParser.java |  40 +++++
 .../servicecomb/authentication/util/Constants.java |  26 +++
 api/edge-service/endpoint/pom.xml                  |  38 ++++
 api/edge-service/pom.xml                           |  36 ++++
 api/edge-service/service/pom.xml                   |  42 +++++
 .../authentication/edge/AuthHandler.java           |  48 +++++
 .../authentication/edge/AuthenticationFilter.java  |  47 +++++
 .../edge/CustomVertxRestDispatcher.java            | 197 +++++++++++++++++++++
 .../authentication/edge/InternalAccessHandler.java |  37 ++++
 ...servicecomb.common.rest.filter.HttpServerFilter |  18 ++
 ...cecomb.transport.rest.vertx.VertxHttpDispatcher |  18 ++
 .../src/main/resources/config/cse.handler.xml      |  23 +++
 api/pom.xml                                        |  92 ++++++++++
 api/resource-server/endpoint/pom.xml               |  38 ++++
 api/resource-server/pom.xml                        |  36 ++++
 api/resource-server/service/pom.xml                |  42 +++++
 .../resource/AccessConfiguration.java              |  37 ++++
 .../resource/AccessConfigurationManager.java       |  36 ++++
 ...eptionExceptionToProducerResponseConverter.java |  39 ++++
 .../resource/ResourceAuthHandler.java              | 101 +++++++++++
 .../resource/SimpleAuthentication.java             |  77 ++++++++
 ....exception.ExceptionToProducerResponseConverter |  18 ++
 .../src/main/resources/config/cse.handler.xml      |  21 +++
 samples/AuthenticationServer/pom.xml               | 168 ++++++++++++++++++
 .../AuthenticationConfiguration.java               |  69 ++++++++
 .../authentication/AuthenticationServerMain.java   |  30 ++++
 .../src/main/resources/log4j2.xml                  |  43 +++++
 .../src/main/resources/microservice.yaml           |  36 ++++
 samples/Client/pom.xml                             | 151 ++++++++++++++++
 .../authentication/AuthenticationClientMain.java   |  30 ++++
 .../authentication/AuthenticationTestCase.java     | 186 +++++++++++++++++++
 .../authentication/BootEventListener.java          |  45 +++++
 .../authentication/GateRestTemplate.java           | 111 ++++++++++++
 .../authentication/ITUriTemplateHandler.java       |  44 +++++
 .../servicecomb/authentication/TestCase.java       |  22 +++
 .../servicecomb/authentication/TestEndpoint.java   |  52 ++++++
 .../apache/servicecomb/authentication/TestMgr.java | 118 ++++++++++++
 samples/Client/src/main/resources/log4j2.xml       |  43 +++++
 .../Client/src/main/resources/microservice.yaml    |  36 ++++
 samples/EdgeService/pom.xml                        | 111 ++++++++++++
 .../authentication/gateway/ApiDispatcher.java      |  69 ++++++++
 .../gateway/AuthenticationConfiguration.java       |  31 ++++
 .../gateway/AuthenticationEdgeMain.java            |  26 +++
 .../authentication/gateway/EdgeSSLCustom.java      |  38 ++++
 .../gateway/StaticWebpageDispatcher.java           |  52 ++++++
 ...cecomb.transport.rest.vertx.VertxHttpDispatcher |  19 ++
 samples/EdgeService/src/main/resources/log4j2.xml  |  43 +++++
 .../src/main/resources/microservice.yaml           |  71 ++++++++
 .../src/main/resources/ui/css/style.css            |  49 +++++
 .../src/main/resources/ui/js/jquery-1.11.1.min.js  |   4 +
 .../EdgeService/src/main/resources/ui/js/login.js  |  52 ++++++
 .../EdgeService/src/main/resources/ui/js/upload.js |  63 +++++++
 .../EdgeService/src/main/resources/ui/login.html   |  45 +++++
 .../EdgeService/src/main/resources/ui/upload.html  |  61 +++++++
 .../authentication/test/PatternTest.java           |  36 ++++
 samples/ResourceServer/pom.xml                     | 142 +++++++++++++++
 .../resource/AuthenticationConfiguration.java      |  31 ++++
 .../authentication/resource/FileEndpoint.java      |  45 +++++
 .../authentication/resource/FileStoreService.java  |  31 ++++
 .../resource/HandlerAuthEndpoint.java              |  46 +++++
 .../resource/LocalFileStoreService.java            |  64 +++++++
 .../resource/MethodSecurityConfiguration.java      |  36 ++++
 .../resource/PreMethodAuthEndpoint.java            |  50 ++++++
 .../resource/ResourceServerMain.java               |  30 ++++
 .../ResourceServer/src/main/resources/log4j2.xml   |  43 +++++
 .../src/main/resources/microservice.yaml           |  51 ++++++
 samples/pom.xml                                    |  92 ++++++++++
 85 files changed, 4819 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..044d558
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,82 @@
+# Output Directory
+target/
+
+# C pre-compile
+*.gch
+*.pch
+
+# C compile
+*.a
+*.o
+*.ko
+*.la
+*.lo
+*.obj
+*.elf
+*.so
+*.so.*
+*.dylib
+*.exe
+*.lib
+*.dll
+*.out
+*.app
+*.hex
+
+# Debug files
+*.dSYM/
+
+# Java
+*.class
+
+# Java Package Files
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+# Zip Files
+*.rar
+*.zip
+*.7z
+*.tar
+*.gz
+
+# Ant
+build/
+
+# Compiled Python
+__pycache__/
+*.py[cod]
+*py.class
+
+# Eclipse
+.settings/
+.classpath
+.project
+
+# IntelliJ, based on http://devnet.jetbrains.net/docs/DOC-1186
+.idea/
+*.iml
+*.ipr
+*.iws
+
+# logs and trace
+*.log
+*.trace
+*.dat
+
+# vi swap
+*.swp
+
+# Backup Files
+*.bak
+*.old
+
+# SVN metadata
+.svn/
+
+# Mac
+.DS_Store
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c91d67e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,110 @@
+This project demonstrates authentications and authorizations based on JWT/OAuth2. Projct names follow OAuth2 architecture. 
+
+## Implementations
+
+This project uses spring security API and mainly designed for ServiceComb architecture.
+
+* User Management
+
+  1. UserDetailsService: load users information
+  2. UserDetails: User information
+  3. GrantedAuthority: authorities
+  4. PasswordEncoder: encode or verify user password
+
+## Project
+
+* AuthenticationServer
+
+Authentication server implementation. Provides APIs to login, and query roles, etc. 
+
+
+* Gateway
+
+Check if users are authenticated and dispatch HTTP request.
+
+* Client
+
+Demonstrates how client uses this project. Integration tests are provided. 
+
+
+* Api
+Reusable part. 
+
+* For testing
+
+Run AuthenticationServer、Gateway、Client、ResourceServer and call
+
+```
+http://localhost:9093/v1/test/start
+```
+
+see AuthenticationTestCase for details.
+
+
+本项目提供认证鉴权服务的实现,主要提供了基于角色的权限管理,和基于JWT的微服务授权模式。微服务的命名参考了OAuth2协议里面的命名方式。可以参考[OAuth2.0原理和验证流程分析](https://www.jianshu.com/p/d74ce6ca0c33)对于OAuth2认证过程的介绍,本项目的认证过程非常类似OAuth2的密码模式。
+
+项目的目标是提供一个商业可用的鉴权实现,对于项目代码实现的问题可以提交issue,本项目也接纳PR,共同完善。
+
+
+
+## 实现说明
+
+* 用户管理
+用户管理采用了org.springframework.security.core.userdetails的模型,包括:
+  1. UserDetailsService:加载用户信息。
+  2. UserDetails:用户信息。
+  3. GrantedAuthority:角色信息。
+  4. PasswordEncoder:用户密码加密和匹配。
+  
+  
+## 项目结构介绍
+
+* AuthenticationServer
+
+认证鉴权服务。提供用户管理、角色管理。并提供登录认证、权限查询等接口。鉴权服务及相关API是核心交付件,也是能够被重用的部分。开发者可以基于这个项目开发认证鉴权服务。
+
+* Gateway
+提供请求拦截,校验用户是否已经经过认证。一方面演示网关如何和配套鉴权服务完成开发,本项目也是自动化测试的组成部分。
+
+* Client
+Client模拟的是使用使用者。一方面演示客户端如何获取Token,本项目也是自动化测试的组成部分。
+
+* ResourceServer
+ResourceServer模拟的是业务服务。一方面演示业务服务如何进行权限配置,本项目也是自动化测试的组成部分。
+
+* Api
+认证鉴权提取的公共功能,作为复用单元。目前项目处于初始阶段,很多复用代码分散在其他项目中。
+
+
+* 测试介绍
+
+本项目实现了微服务架构的自动化测试。启动AuthenticationServer、Gateway、Client、ResourceServer后,可以提供
+
+```
+http://localhost:9093/v1/test/start
+```
+触发测试用例的执行。 所有的测试用例放到Client微服务里面, 这个微服务实现了简单的测试框架帮助书写测试用例,对测试结果进行检查等功能。 
+
+测试项目同时展示了这个项目的功能,比如: AuthenticationTestCase 的测试逻辑展示了基本的认证功能,从登陆,到接口的权限检查。 
+
+# TODO LIST
+1. provide TLS for authentication server & edge service
+2. grant scope for INTERNAL access & EXTERNAL access 
+3. access token support: a. use access token to get optional scope or roles token. 这个可以解决角色过多的时候, token过大的一些问题
+4. 实现注销逻辑(会话管理)
+5. 支持分层的角色机制
+
+       ROLE_LEVEL1
+        /       \
+   ROLE_LEVEL2  ROLE_LEVEL2
+
+ TOKEN里面只返回ROLE_LEVEL1,设置为ROLE_LEVEL2访问的操作,也可以访问。
+
+6. REFRESH_TOKEN可以用来实现申请不同SCOPE的TOKEN。 
+7. 设计目标:无状态。认证服务器和资源服务器均可以多实例部署,每个实例之间不共享状态。在实现很多功能的时候,都遵循这个约束。包括通过refresh token获取新的access token的时候。遵循这个约束,意味着请求需要同时传递refresh token和access token。 
+8, 重新设计TOKEN(代码重构、支持会话管理),支持OpenID Connect。
+
+OAUTH的不好的地方:TOKEN在有效期内,容易被利用,无法注销;TOKEN过期后,必须重新认证,和用户是否在一直操作无关,体验不好,虽然可以通过refresh_token获取新的token提升体验,但是refresh_token有效期如果设置的太长,会降低安全性。Token在有效期内,如果修改了权限等信息,无法及时感知,需要重新登录。
+OAUTH的好的地方:TOKEN签发、认证都可以由微服务实例独自完成,不需要共用的数据存储,比如数据库、Redis等,效率更高,弹性扩容。
+
+
diff --git a/api/authentication-server/endpoint/pom.xml b/api/authentication-server/endpoint/pom.xml
new file mode 100644
index 0000000..a653462
--- /dev/null
+++ b/api/authentication-server/endpoint/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-server-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-server-api-endpoint</artifactId>
+  <packaging>jar</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-server-api-service</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-common-api-service</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
new file mode 100644
index 0000000..7d16268
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.jwt.Jwt;
+import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.stereotype.Component;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+@Component(value = "passwordTokenGranter")
+public class PasswordTokenGranter implements TokenGranter {
+  @Autowired
+  @Qualifier("authUserDetailsService")
+  private UserDetailsService userDetailsService;
+
+  @Autowired
+  @Qualifier("authPasswordEncoder")
+  private PasswordEncoder passwordEncoder;
+
+  @Autowired
+  @Qualifier("authSigner")
+  private Signer signer;
+
+  @Override
+  public Token grant(Map<String, String> parameters) {
+    String username = parameters.get(TokenConst.PARAM_USERNAME);
+    String password = parameters.get(TokenConst.PARAM_PASSWORD);
+
+    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+    if (passwordEncoder.matches(password, userDetails.getPassword())) {
+      JWTClaims claims = new JWTClaims();
+      if (userDetails.getAuthorities() != null) {
+        userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority()));
+      }
+      claims.setJti(UUID.randomUUID().toString());
+      claims.setIat(System.currentTimeMillis());
+      claims.setExp(5 * 60);
+      
+      String content = JsonParser.unparse(claims);
+      Jwt accessToken = JwtHelper.encode(content, signer);
+
+      Token token = new Token();
+      token.setScope(claims.getScope());
+      token.setExpires_in(10 * 60);
+      token.setToken_type("bearer");
+      token.setAccess_token(accessToken.getEncoded());
+      
+      JWTClaims accessTokenClaims = new JWTClaims();
+      accessTokenClaims.setJti(UUID.randomUUID().toString());
+      accessTokenClaims.setIat(System.currentTimeMillis());
+      accessTokenClaims.setExp(60 * 60);
+      Jwt refreshToken = JwtHelper.encode(JsonParser.unparse(claims), signer);
+      token.setRefresh_token(refreshToken.getEncoded());
+      
+      return token;
+    } else {
+      return null;
+    }
+  }
+
+  @Override
+  public String grantType() {
+    return TokenConst.GRANT_TYPE_PASSWORD;
+  }
+
+  @Override
+  public boolean enabled() {
+    return DynamicPropertyFactory.getInstance()
+        .getBooleanProperty("servicecomb.authentication.granter.password.enabled", true)
+        .get();
+  }
+
+}
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
new file mode 100644
index 0000000..ffbf9c5
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+import java.util.Map;
+
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.jwt.Jwt;
+import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
+import org.springframework.stereotype.Component;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+@Component(value = "fefreshTokenTokenGranter")
+public class RefreshTokenTokenGranter implements TokenGranter {
+  @Autowired
+  @Qualifier("authSignerVerifier")
+  private SignerVerifier signerVerifier;
+
+  @Autowired
+  @Qualifier("authSigner")
+  private Signer signer;
+
+  @Override
+  public boolean enabled() {
+    return DynamicPropertyFactory.getInstance()
+        .getBooleanProperty("servicecomb.authentication.granter.refreshToken.enabled", true)
+        .get();
+  }
+
+  @Override
+  public String grantType() {
+    return TokenConst.GRANT_TYPE_REFRESH_TOKEN;
+  }
+
+  @Override
+  public Token grant(Map<String, String> parameters) {
+    String refreshToken = parameters.get(TokenConst.PARAM_REFRESH_TOKEN);
+    String accessToken = parameters.get(TokenConst.PARAM_ACCESS_TOKEN);
+
+    // verify refresh tokens
+    Jwt jwt = JwtHelper.decode(refreshToken);
+    JWTClaims claims;
+    try {
+      jwt.verifySignature(signerVerifier);
+      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
+      // TODO: verify claims.
+    } catch (Exception e) {
+      return null;
+    }
+
+    // verify access tokens
+    jwt = JwtHelper.decode(accessToken);
+    claims = null;
+    try {
+      jwt.verifySignature(signerVerifier);
+      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
+      // TODO: verify claims.
+    } catch (Exception e) {
+      return null;
+    }
+
+    claims.setIat(System.currentTimeMillis());
+    String content = JsonParser.unparse(claims);
+    Jwt newAccessToken = JwtHelper.encode(content, signer);
+
+    Token token = new Token();
+    token.setScope(claims.getScope());
+    token.setExpires_in(10 * 60);
+    token.setToken_type("bearer");
+    token.setAccess_token(newAccessToken.getEncoded());
+    return token;
+  }
+
+}
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java
new file mode 100644
index 0000000..775d332
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@RestSchema(schemaId = "TokenEndpoint")
+@RequestMapping(path = "/v1/oauth/token")
+public class TokenEndpoint implements TokenService {
+  @Autowired
+  private List<TokenGranter> granters;
+
+  @Override
+  @PostMapping(path = "/", consumes = MediaType.APPLICATION_FORM_URLENCODED)
+  public Token getAccessToken(@RequestBody Map<String, String> parameters) {
+    String grantType = parameters.get(TokenConst.PARAM_GRANT_TYPE);
+
+    for (TokenGranter granter : granters) {
+      if (granter.enabled()) {
+        Token token = granter.grant(grantType, parameters);
+        if (token != null) {
+          return token;
+        }
+      }
+    }
+
+    return null;
+  }
+
+}
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
new file mode 100644
index 0000000..9ba0861
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenGranter.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+import java.util.Map;
+
+/**
+ * Token granter is used to grant access tokens. 
+ * @author Administrator
+ *
+ */
+public interface TokenGranter {
+  boolean enabled();
+
+  String grantType();
+
+  default Token grant(String grantType, Map<String, String> parameters) {
+    if (grantType().equals(grantType)) {
+      return grant(parameters);
+    }
+    return null;
+  }
+
+  Token grant(Map<String, String> parameters);
+}
diff --git a/api/authentication-server/pom.xml b/api/authentication-server/pom.xml
new file mode 100644
index 0000000..946a2fb
--- /dev/null
+++ b/api/authentication-server/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-server-api</artifactId>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>service</module>
+    <module>endpoint</module>
+  </modules>
+</project>
\ No newline at end of file
diff --git a/api/authentication-server/service/pom.xml b/api/authentication-server/service/pom.xml
new file mode 100644
index 0000000..4433ff6
--- /dev/null
+++ b/api/authentication-server/service/pom.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-server-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-server-api-service</artifactId>
+  <packaging>jar</packaging>
+
+</project>
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java
new file mode 100644
index 0000000..8758bd1
--- /dev/null
+++ b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+import java.util.Map;
+import java.util.Set;
+
+public class Token {
+  // Naming conventions https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-00#section-3.1
+  private String token_type;
+
+  private String access_token;
+
+  private String refresh_token;
+
+  private int expires_in;
+
+  private Set<String> scope;
+
+  // JWT id
+  private String jti;
+
+  private Map<String, Object> additionalInformation;
+
+  public String getToken_type() {
+    return token_type;
+  }
+
+  public void setToken_type(String token_type) {
+    this.token_type = token_type;
+  }
+
+  public String getAccess_token() {
+    return access_token;
+  }
+
+  public void setAccess_token(String access_token) {
+    this.access_token = access_token;
+  }
+
+  public String getRefresh_token() {
+    return refresh_token;
+  }
+
+  public void setRefresh_token(String refresh_token) {
+    this.refresh_token = refresh_token;
+  }
+
+  public int getExpires_in() {
+    return expires_in;
+  }
+
+  public void setExpires_in(int expires_in) {
+    this.expires_in = expires_in;
+  }
+
+  public Set<String> getScope() {
+    return scope;
+  }
+
+  public void setScope(Set<String> scope) {
+    this.scope = scope;
+  }
+
+  public String getJti() {
+    return jti;
+  }
+
+  public void setJti(String jti) {
+    this.jti = jti;
+  }
+
+  public Map<String, Object> getAdditionalInformation() {
+    return additionalInformation;
+  }
+
+  public void setAdditionalInformation(Map<String, Object> additionalInformation) {
+    this.additionalInformation = additionalInformation;
+  }
+
+}
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java
new file mode 100644
index 0000000..915a515
--- /dev/null
+++ b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+public class TokenConst {
+  public static final String PARAM_GRANT_TYPE = "grant_type";
+
+  public static final String PARAM_USERNAME = "username";
+
+  public static final String PARAM_PASSWORD = "password";
+
+  public static final String PARAM_REFRESH_TOKEN = "refresh_token";
+
+  public static final String PARAM_ACCESS_TOKEN = "access_token";
+
+  public static final String GRANT_TYPE_PASSWORD = "password";
+  
+  public static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
+}
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
new file mode 100644
index 0000000..b0cea22
--- /dev/null
+++ b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.server;
+
+import java.util.Map;
+
+public interface TokenService {
+  Token getAccessToken(Map<String, String> parameters);
+}
diff --git a/api/common/endpoint/pom.xml b/api/common/endpoint/pom.xml
new file mode 100644
index 0000000..de2736a
--- /dev/null
+++ b/api/common/endpoint/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-common-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-common-api-endpoint</artifactId>
+  <packaging>jar</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-common-api-service</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/api/common/pom.xml b/api/common/pom.xml
new file mode 100644
index 0000000..b4a9fbc
--- /dev/null
+++ b/api/common/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-common-api</artifactId>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>service</module>
+    <module>endpoint</module>
+  </modules>
+</project>
\ No newline at end of file
diff --git a/api/common/service/pom.xml b/api/common/service/pom.xml
new file mode 100644
index 0000000..66c5f90
--- /dev/null
+++ b/api/common/service/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-common-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-common-api-service</artifactId>
+  <packaging>jar</packaging>
+
+ <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.springframework.security.oauth</groupId>
+        <artifactId>spring-security-oauth2</artifactId>
+        <version>2.3.2.RELEASE</version>
+      </dependency>
+      <dependency>
+        <groupId>org.springframework.security</groupId>
+        <artifactId>spring-security-jwt</artifactId>
+        <version>1.0.7.RELEASE</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.springframework.security.oauth</groupId>
+      <artifactId>spring-security-oauth2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-jwt</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTClaims.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTClaims.java
new file mode 100644
index 0000000..c62affc
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTClaims.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.jwt;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class JWTClaims extends JWTClaimsCommon {
+  protected Set<String> authorities;
+
+  protected Map<String, Object> additionalInformation;
+
+  /**
+   * The scope of the access token as described by <a
+   * href="http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.3">Section 3.3</a>
+   */
+  protected Set<String> scope;
+
+  public Set<String> getAuthorities() {
+    return authorities;
+  }
+
+  public void setAuthorities(Set<String> authorities) {
+    this.authorities = authorities;
+  }
+
+  public Map<String, Object> getAdditionalInformation() {
+    return additionalInformation;
+  }
+
+  public void setAdditionalInformation(Map<String, Object> additionalInformation) {
+    this.additionalInformation = additionalInformation;
+  }
+
+  public Set<String> getScope() {
+    return scope;
+  }
+
+  public void setScope(Set<String> scope) {
+    this.scope = scope;
+  }
+
+  public void addAdditionalInformation(String key, Object value) {
+    if (this.additionalInformation == null) {
+      this.additionalInformation = new HashMap<>();
+    }
+    this.additionalInformation.put(key, value);
+  }
+
+  public void addScope(String operation) {
+    if (this.scope == null) {
+      this.scope = new HashSet<>();
+    }
+    this.scope.add(operation);
+  }
+
+  public void addAuthority(String authority) {
+    if (this.authorities == null) {
+      this.authorities = new HashSet<>();
+    }
+    this.authorities.add(authority);
+  }
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTClaimsCommon.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTClaimsCommon.java
new file mode 100644
index 0000000..54e26a5
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTClaimsCommon.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.jwt;
+
+public class JWTClaimsCommon {
+  // see: https://tools.ietf.org/html/rfc7519
+  // (Issuer) Claim
+  protected String iss;
+
+  // (Subject) Claim
+  protected String sub;
+
+  // (Audience) Claim
+  protected String aud;
+
+  // (Expiration Time) Claim
+  protected long exp;
+
+  // (Not Before) Claim
+  protected long nbf;
+
+  // (Issued At) Claim
+  protected long iat;
+
+  // (JWT ID) Claim
+  protected String jti;
+
+  public String getIss() {
+    return iss;
+  }
+
+  public void setIss(String iss) {
+    this.iss = iss;
+  }
+
+  public String getSub() {
+    return sub;
+  }
+
+  public void setSub(String sub) {
+    this.sub = sub;
+  }
+
+  public String getAud() {
+    return aud;
+  }
+
+  public void setAud(String aud) {
+    this.aud = aud;
+  }
+
+  public long getExp() {
+    return exp;
+  }
+
+  public void setExp(long exp) {
+    this.exp = exp;
+  }
+
+  public long getNbf() {
+    return nbf;
+  }
+
+  public void setNbf(long nbf) {
+    this.nbf = nbf;
+  }
+
+  public long getIat() {
+    return iat;
+  }
+
+  public void setIat(long iat) {
+    this.iat = iat;
+  }
+
+  public String getJti() {
+    return jti;
+  }
+
+  public void setJti(String jti) {
+    this.jti = jti;
+  }
+
+
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTHeader.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTHeader.java
new file mode 100644
index 0000000..2cc797c
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JWTHeader.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.jwt;
+
+public class JWTHeader {
+  private String typ;
+
+  private String alg;
+
+  public String getTyp() {
+    return typ;
+  }
+
+  public void setTyp(String typ) {
+    this.typ = typ;
+  }
+
+  public String getAlg() {
+    return alg;
+  }
+
+  public void setAlg(String alg) {
+    this.alg = alg;
+  }
+
+
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JsonParser.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JsonParser.java
new file mode 100644
index 0000000..2a4bcd1
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/jwt/JsonParser.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.jwt;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class JsonParser {
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+
+  public static <T> T parse(String json, Class<T> clazz) {
+    try {
+      return MAPPER.readValue(json, clazz);
+    } catch (Exception e) {
+      throw new IllegalArgumentException("Cannot parse json", e);
+    }
+  }
+
+  public static <T> String unparse(T obj) {
+    try {
+      return MAPPER.writeValueAsString(obj);
+    } catch (Exception e) {
+      throw new IllegalArgumentException("Cannot unparse json", e);
+    }
+  }
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java
new file mode 100644
index 0000000..96333aa
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.util;
+
+public final class Constants {
+  public static final String HTTP_HEADER_AUTHORIZATION = "Authorization";
+
+  public static final String CONTEXT_HEADER_AUTHORIZATION = "Authorization";
+  
+  public static final String CONTEXT_HEADER_CLAIMS = "Claims";
+}
diff --git a/api/edge-service/endpoint/pom.xml b/api/edge-service/endpoint/pom.xml
new file mode 100644
index 0000000..66c4a87
--- /dev/null
+++ b/api/edge-service/endpoint/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Licensed to the Apache Software Foundation (ASF) under one or more 
+  ~ contributor license agreements. See the NOTICE file distributed with ~ 
+  this work for additional information regarding copyright ownership. ~ The 
+  ASF licenses this file to You under the Apache License, Version 2.0 ~ (the 
+  "License"); you may not use this file except in compliance with ~ the License. 
+  You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 
+  ~ ~ Unless required by applicable law or agreed to in writing, software ~ 
+  distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT 
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the 
+  License for the specific language governing permissions and ~ limitations 
+  under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-server-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-edge-api-endpoint</artifactId>
+  <packaging>jar</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-edge-api-service</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-server-api-service</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/api/edge-service/pom.xml b/api/edge-service/pom.xml
new file mode 100644
index 0000000..24d393b
--- /dev/null
+++ b/api/edge-service/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-edge-api</artifactId>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>service</module>
+    <module>endpoint</module>
+  </modules>
+</project>
\ No newline at end of file
diff --git a/api/edge-service/service/pom.xml b/api/edge-service/service/pom.xml
new file mode 100644
index 0000000..8d86c00
--- /dev/null
+++ b/api/edge-service/service/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Licensed to the Apache Software Foundation (ASF) under one or more 
+  ~ contributor license agreements. See the NOTICE file distributed with ~ 
+  this work for additional information regarding copyright ownership. ~ The 
+  ASF licenses this file to You under the Apache License, Version 2.0 ~ (the 
+  "License"); you may not use this file except in compliance with ~ the License. 
+  You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 
+  ~ ~ Unless required by applicable law or agreed to in writing, software ~ 
+  distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT 
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the 
+  License for the specific language governing permissions and ~ limitations 
+  under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-edge-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-edge-api-service</artifactId>
+  <packaging>jar</packaging>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-common-api-endpoint</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-common-api-endpoint</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
new file mode 100644
index 0000000..40ef32d
--- /dev/null
+++ b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.edge;
+
+import org.apache.servicecomb.authentication.util.Constants;
+import org.apache.servicecomb.core.Handler;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.common.utils.BeanUtils;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.springframework.security.jwt.Jwt;
+import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.InvalidSignatureException;
+
+
+public class AuthHandler implements Handler {
+  @Override
+  public void handle(Invocation invocation, AsyncResponse asyncResponse) throws Exception {
+    String token = invocation.getContext(Constants.CONTEXT_HEADER_AUTHORIZATION);
+    if (token == null) {
+      asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
+      return;
+    }
+    Jwt jwt = JwtHelper.decode(token);
+    try {
+      jwt.verifySignature(BeanUtils.getBean("authSignerVerifier"));
+    } catch (InvalidSignatureException e) {
+      asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
+      return;
+    }
+    invocation.next(asyncResponse);
+  }
+}
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java
new file mode 100644
index 0000000..46ba288
--- /dev/null
+++ b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.edge;
+
+import org.apache.servicecomb.authentication.util.Constants;
+import org.apache.servicecomb.common.rest.filter.HttpServerFilter;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
+import org.apache.servicecomb.swagger.invocation.Response;
+
+public class AuthenticationFilter implements HttpServerFilter {
+
+  @Override
+  public int getOrder() {
+    return 0;
+  }
+
+  @Override
+  public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) {
+    String authentication = requestEx.getHeader(Constants.HTTP_HEADER_AUTHORIZATION);
+    if (authentication != null) {
+      String[] tokens = authentication.split(" ");
+      if (tokens.length == 2) {
+        if (tokens[0].equals("Bearer")) {
+          invocation.addContext(Constants.CONTEXT_HEADER_AUTHORIZATION, tokens[1]);
+        }
+      }
+    }
+    return null;
+  }
+
+}
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java
new file mode 100644
index 0000000..521b71c
--- /dev/null
+++ b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.edge;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.Response.Status.Family;
+
+import org.apache.servicecomb.common.rest.AbstractRestInvocation;
+import org.apache.servicecomb.common.rest.RestConst;
+import org.apache.servicecomb.common.rest.VertxRestInvocation;
+import org.apache.servicecomb.core.Const;
+import org.apache.servicecomb.core.CseContext;
+import org.apache.servicecomb.core.Transport;
+import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
+import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
+import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest;
+import org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.apache.servicecomb.transport.rest.vertx.AbstractVertxHttpDispatcher;
+import org.apache.servicecomb.transport.rest.vertx.VertxRestDispatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
+import io.vertx.ext.web.handler.CookieHandler;
+
+// copied from org.apache.servicecomb.transport.rest.vertx.VertxRestDispatcher 1.2.0
+// TODO: using 1.2.2+ to make it simpler
+public class CustomVertxRestDispatcher extends AbstractVertxHttpDispatcher {
+  private static final Logger LOGGER = LoggerFactory.getLogger(VertxRestDispatcher.class);
+
+  private Transport transport;
+
+  @Override
+  public int getOrder() {
+    return 10001;
+  }
+
+  @Override
+  public boolean enabled() {
+    return true;
+  }
+
+  @Override
+  public void init(Router router) {
+    String regex = "(/v1/log|/inspector|/v1/auth)/(.*)";
+    router.routeWithRegex(regex).handler(CookieHandler.create());
+    router.routeWithRegex(regex).handler(createBodyHandler());
+    router.routeWithRegex(regex).failureHandler(this::failureHandler).handler(this::onRequest);
+  }
+
+  private void failureHandler(RoutingContext context) {
+    LOGGER.error("http server failed.", context.failure());
+
+    AbstractRestInvocation restProducerInvocation = context.get(RestConst.REST_PRODUCER_INVOCATION);
+    Throwable e = context.failure();
+    if (ErrorDataDecoderException.class.isInstance(e)) {
+      Throwable cause = e.getCause();
+      if (InvocationException.class.isInstance(cause)) {
+        e = cause;
+      }
+    }
+
+    // only when unexpected exception happens, it will run into here.
+    // the connection should be closed.
+    handleFailureAndClose(context, restProducerInvocation, e);
+  }
+
+  /**
+   * Try to find out the failure information and send it in response.
+   */
+  private void handleFailureAndClose(RoutingContext context, AbstractRestInvocation restProducerInvocation,
+      Throwable e) {
+    if (null != restProducerInvocation) {
+      // if there is restProducerInvocation, let it send exception in response. The exception is allowed to be null.
+      sendFailResponseByInvocation(context, restProducerInvocation, e);
+      return;
+    }
+
+    if (null != e) {
+      // if there exists exception, try to send this exception by RoutingContext
+      sendExceptionByRoutingContext(context, e);
+      return;
+    }
+
+    // if there is no exception, the response is determined by status code.
+    sendFailureRespDeterminedByStatus(context);
+  }
+
+  /**
+   * Try to determine response by status code, and send response.
+   */
+  private void sendFailureRespDeterminedByStatus(RoutingContext context) {
+    Family statusFamily = Family.familyOf(context.statusCode());
+    if (Family.CLIENT_ERROR.equals(statusFamily) || Family.SERVER_ERROR.equals(statusFamily) || Family.OTHER
+        .equals(statusFamily)) {
+      context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)
+          .setStatusCode(context.statusCode()).end();
+    } else {
+      // it seems the status code is not set properly
+      context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)
+          .setStatusCode(Status.INTERNAL_SERVER_ERROR.getStatusCode())
+          .setStatusMessage(Status.INTERNAL_SERVER_ERROR.getReasonPhrase())
+          .end(wrapResponseBody(Status.INTERNAL_SERVER_ERROR.getReasonPhrase()));
+    }
+    context.response().close();
+  }
+
+  /**
+   * Use routingContext to send failure information in throwable.
+   */
+  private void sendExceptionByRoutingContext(RoutingContext context, Throwable e) {
+    if (InvocationException.class.isInstance(e)) {
+      InvocationException invocationException = (InvocationException) e;
+      context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)
+          .setStatusCode(invocationException.getStatusCode()).setStatusMessage(invocationException.getReasonPhrase())
+          .end(wrapResponseBody(invocationException.getReasonPhrase()));
+    } else {
+      context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)
+          .setStatusCode(Status.INTERNAL_SERVER_ERROR.getStatusCode()).end(wrapResponseBody(e.getMessage()));
+    }
+    context.response().close();
+  }
+
+  /**
+   * Consumer will treat the response body as json by default, so it's necessary to wrap response body as Json string
+   * to avoid deserialization error.
+   *
+   * @param message response body
+   * @return response body wrapped as Json string
+   */
+  String wrapResponseBody(String message) {
+    if (isValidJson(message)) {
+      return message;
+    }
+
+    JsonObject jsonObject = new JsonObject();
+    jsonObject.put("message", message);
+
+    return jsonObject.toString();
+  }
+
+  /**
+   * Check if the message is a valid Json string.
+   * @param message the message to be checked.
+   * @return true if message is a valid Json string, otherwise false.
+   */
+  private boolean isValidJson(String message) {
+    try {
+      new JsonObject(message);
+    } catch (Exception ignored) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Use restProducerInvocation to send failure message. The throwable is allowed to be null.
+   */
+  private void sendFailResponseByInvocation(RoutingContext context, AbstractRestInvocation restProducerInvocation,
+      Throwable e) {
+    restProducerInvocation.sendFailResponse(e);
+    context.response().close();
+  }
+
+  private void onRequest(RoutingContext context) {
+    if (transport == null) {
+      transport = CseContext.getInstance().getTransportManager().findTransport(Const.RESTFUL);
+    }
+    HttpServletRequestEx requestEx = new VertxServerRequestToHttpServletRequest(context);
+    HttpServletResponseEx responseEx = new VertxServerResponseToHttpServletResponse(context.response());
+
+    VertxRestInvocation vertxRestInvocation = new VertxRestInvocation();
+    context.put(RestConst.REST_PRODUCER_INVOCATION, vertxRestInvocation);
+    vertxRestInvocation.invoke(transport, requestEx, responseEx, httpServerFilters);
+  }
+}
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/InternalAccessHandler.java b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/InternalAccessHandler.java
new file mode 100644
index 0000000..d01620f
--- /dev/null
+++ b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/InternalAccessHandler.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.edge;
+
+import org.apache.servicecomb.core.Handler;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+
+public class InternalAccessHandler implements Handler {
+
+  @Override
+  public void handle(Invocation invocation, AsyncResponse asyncReponse) throws Exception {
+    if (invocation.getOperationMeta().getSwaggerOperation().getTags() != null
+        && invocation.getOperationMeta().getSwaggerOperation().getTags().contains("INTERNAL")) {
+      asyncReponse.consumerFail(new InvocationException(403, "", "not allowed"));
+      return;
+    }
+    invocation.next(asyncReponse);
+  }
+
+}
diff --git a/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter b/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter
new file mode 100644
index 0000000..75e40b9
--- /dev/null
+++ b/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.servicecomb.authentication.edge.AuthenticationFilter
\ No newline at end of file
diff --git a/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher b/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
new file mode 100644
index 0000000..32c1583
--- /dev/null
+++ b/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# org.apache.servicecomb.authentication.edge.CustomVertxRestDispatcher
\ No newline at end of file
diff --git a/api/edge-service/service/src/main/resources/config/cse.handler.xml b/api/edge-service/service/src/main/resources/config/cse.handler.xml
new file mode 100644
index 0000000..43a5258
--- /dev/null
+++ b/api/edge-service/service/src/main/resources/config/cse.handler.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<config>
+  <handler id="auth"
+    class="org.apache.servicecomb.authentication.edge.AuthHandler" />
+  <handler id="internalAccess"
+    class="org.apache.servicecomb.authentication.edge.InternalAccessHandler" />
+</config>
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000..92c7f27
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.servicecomb.authentication</groupId>
+  <artifactId>authentication-api</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <modules>
+    <module>common</module>
+    <module>authentication-server</module>
+    <module>resource-server</module>
+    <module>edge-service</module>
+  </modules>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.servicecomb</groupId>
+        <artifactId>java-chassis-dependencies</artifactId>
+        <version>1.2.0</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>solution-basic</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>inspector</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.8</source>
+            <target>1.8</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-maven-plugin</artifactId>
+          <version>2.1.2.RELEASE</version>
+          <executions>
+            <execution>
+              <goals>
+                <goal>repackage</goal>
+              </goals>
+              <configuration>
+                <mainClass>${main.class}</mainClass>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
\ No newline at end of file
diff --git a/api/resource-server/endpoint/pom.xml b/api/resource-server/endpoint/pom.xml
new file mode 100644
index 0000000..dc5d549
--- /dev/null
+++ b/api/resource-server/endpoint/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-resource-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-resource-api-endpoint</artifactId>
+  <packaging>jar</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-resource-api-service</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/api/resource-server/pom.xml b/api/resource-server/pom.xml
new file mode 100644
index 0000000..7c3f228
--- /dev/null
+++ b/api/resource-server/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-resource-api</artifactId>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>service</module>
+    <module>endpoint</module>
+  </modules>
+</project>
\ No newline at end of file
diff --git a/api/resource-server/service/pom.xml b/api/resource-server/service/pom.xml
new file mode 100644
index 0000000..cf045ce
--- /dev/null
+++ b/api/resource-server/service/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Licensed to the Apache Software Foundation (ASF) under one or more 
+  ~ contributor license agreements. See the NOTICE file distributed with ~ 
+  this work for additional information regarding copyright ownership. ~ The 
+  ASF licenses this file to You under the Apache License, Version 2.0 ~ (the 
+  "License"); you may not use this file except in compliance with ~ the License. 
+  You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 
+  ~ ~ Unless required by applicable law or agreed to in writing, software ~ 
+  distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT 
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the 
+  License for the specific language governing permissions and ~ limitations 
+  under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-resource-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-resource-api-service</artifactId>
+  <packaging>jar</packaging>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-common-api-endpoint</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-common-api-endpoint</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessConfiguration.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessConfiguration.java
new file mode 100644
index 0000000..8167612
--- /dev/null
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessConfiguration.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.apache.servicecomb.config.inject.InjectProperties;
+import org.apache.servicecomb.config.inject.InjectProperty;
+
+@InjectProperties(prefix = "servicecomb.authencation.access")
+public class AccessConfiguration {
+  @InjectProperty(keys = {
+      "needAuth.${schemaId}.${operationId}",
+      "needAuth.${schemaId}",
+      "needAuth"},
+      defaultValue = "true")
+  public boolean needAuth;
+
+  @InjectProperty(keys = {
+      "roles.${schemaId}.${operationId}",
+      "roles.${schemaId}",
+      "roles"})
+  public String roles;
+}
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessConfigurationManager.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessConfigurationManager.java
new file mode 100644
index 0000000..c6ea891
--- /dev/null
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessConfigurationManager.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import java.util.Map;
+
+import org.apache.servicecomb.config.inject.ConfigObjectFactory;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
+
+public class AccessConfigurationManager {
+  private static final Map<String, AccessConfiguration> CONFIGURATIONS = new ConcurrentHashMapEx<>();
+
+  private static final ConfigObjectFactory FACTORY = new ConfigObjectFactory();
+
+  public static AccessConfiguration getAccessConfiguration(Invocation invocation) {
+    return CONFIGURATIONS.computeIfAbsent(invocation.getOperationMeta().getSchemaQualifiedName(), key -> {
+      return FACTORY.create(AccessConfiguration.class, "schemaId", invocation.getSchemaId(), "operationId", invocation.getOperationName());
+    });
+  }
+}
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessDeniedExceptionExceptionToProducerResponseConverter.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessDeniedExceptionExceptionToProducerResponseConverter.java
new file mode 100644
index 0000000..c2decce
--- /dev/null
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/AccessDeniedExceptionExceptionToProducerResponseConverter.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.apache.servicecomb.swagger.invocation.SwaggerInvocation;
+import org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.springframework.security.access.AccessDeniedException;
+
+public class AccessDeniedExceptionExceptionToProducerResponseConverter
+    implements ExceptionToProducerResponseConverter<AccessDeniedException> {
+
+  @Override
+  public Class<AccessDeniedException> getExceptionClass() {
+    return AccessDeniedException.class;
+  }
+
+  @Override
+  public Response convert(SwaggerInvocation swaggerInvocation, AccessDeniedException e) {
+    return Response.failResp(new InvocationException(403, "forbidden", "not authenticated"));
+  }
+
+}
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
new file mode 100644
index 0000000..1d8e32b
--- /dev/null
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.apache.servicecomb.authentication.util.Constants;
+import org.apache.servicecomb.core.Handler;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.common.utils.BeanUtils;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.context.SecurityContextImpl;
+import org.springframework.security.jwt.Jwt;
+import org.springframework.security.jwt.JwtHelper;
+
+public class ResourceAuthHandler implements Handler {
+
+  @Override
+  public void handle(Invocation invocation, AsyncResponse asyncResponse) throws Exception {
+    AccessConfiguration config = AccessConfigurationManager.getAccessConfiguration(invocation);
+
+    // by pass authentication
+    if (!config.needAuth) {
+      invocation.next(asyncResponse);
+      return;
+    }
+
+    String token = invocation.getContext(Constants.CONTEXT_HEADER_AUTHORIZATION);
+    if (token == null) {
+      asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
+      return;
+    }
+    // verify tokens
+    Jwt jwt = JwtHelper.decode(token);
+    JWTClaims claims;
+    try {
+      jwt.verifySignature(BeanUtils.getBean("authSignerVerifier"));
+      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
+      // TODO: verify claims.
+    } catch (Exception e) {
+      asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
+      return;
+    }
+
+    // check roles
+    if (!StringUtils.isEmpty(config.roles)) {
+      String[] roles = config.roles.split(",");
+      if (roles.length > 0) {
+        boolean valid = false;
+        Set<String> authorities = claims.getAuthorities();
+        for (String role : roles) {
+          if (authorities.contains(role)) {
+            valid = true;
+            break;
+          }
+        }
+        if (!valid) {
+          asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
+          return;
+        }
+      }
+    }
+
+    // pre method authentiation
+    Set<GrantedAuthority> grantedAuthorities = new HashSet<>(claims.getAuthorities().size());
+    claims.getAuthorities().forEach(v -> grantedAuthorities.add(new SimpleGrantedAuthority(v)));
+    SecurityContext sc = new SecurityContextImpl();
+    Authentication authentication = new SimpleAuthentication(true, grantedAuthorities);
+    sc.setAuthentication(authentication);
+    SecurityContextHolder.setContext(sc);
+
+    // next
+    invocation.next(asyncResponse);
+  }
+
+}
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/SimpleAuthentication.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/SimpleAuthentication.java
new file mode 100644
index 0000000..a23404c
--- /dev/null
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/SimpleAuthentication.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import java.util.Collection;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+public class SimpleAuthentication implements Authentication {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 6077733273349249822L;
+
+  private boolean authenticated;
+
+  private Collection<? extends GrantedAuthority> authorities;
+
+  public SimpleAuthentication(boolean authenticated, Collection<? extends GrantedAuthority> authorities) {
+    this.authenticated = authenticated;
+    this.authorities = authorities;
+  }
+
+
+  @Override
+  public String getName() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Collection<? extends GrantedAuthority> getAuthorities() {
+    return this.authorities;
+  }
+
+  @Override
+  public Object getCredentials() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Object getDetails() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Object getPrincipal() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean isAuthenticated() {
+    return this.authenticated;
+  }
+
+  @Override
+  public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+}
diff --git a/api/resource-server/service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter b/api/resource-server/service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter
new file mode 100644
index 0000000..e6ad477
--- /dev/null
+++ b/api/resource-server/service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.servicecomb.authentication.resource.AccessDeniedExceptionExceptionToProducerResponseConverter
\ No newline at end of file
diff --git a/api/resource-server/service/src/main/resources/config/cse.handler.xml b/api/resource-server/service/src/main/resources/config/cse.handler.xml
new file mode 100644
index 0000000..0efe6d1
--- /dev/null
+++ b/api/resource-server/service/src/main/resources/config/cse.handler.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<config>
+  <handler id="resource-auth-provider"
+    class="org.apache.servicecomb.authentication.resource.ResourceAuthHandler" />
+</config>
diff --git a/samples/AuthenticationServer/pom.xml b/samples/AuthenticationServer/pom.xml
new file mode 100644
index 0000000..488d06d
--- /dev/null
+++ b/samples/AuthenticationServer/pom.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Licensed to the Apache Software Foundation (ASF) under one or more 
+  ~ contributor license agreements. See the NOTICE file distributed with ~ 
+  this work for additional information regarding copyright ownership. ~ The 
+  ASF licenses this file to You under the Apache License, Version 2.0 ~ (the 
+  "License"); you may not use this file except in compliance with ~ the License. 
+  You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 
+  ~ ~ Unless required by applicable law or agreed to in writing, software ~ 
+  distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT 
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the 
+  License for the specific language governing permissions and ~ limitations 
+  under the License. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-samples</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>authentication-server</artifactId>
+  <packaging>jar</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.mybatis</groupId>
+        <artifactId>mybatis</artifactId>
+        <version>3.4.5</version>
+      </dependency>
+      <dependency>
+        <groupId>org.mybatis</groupId>
+        <artifactId>mybatis-spring</artifactId>
+        <version>1.3.0</version>
+      </dependency>
+      <dependency>
+        <groupId>mysql</groupId>
+        <artifactId>mysql-connector-java</artifactId>
+        <version>5.1.46</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-server-api-endpoint</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-common-api-endpoint</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb</groupId>
+        <artifactId>java-chassis-dependencies</artifactId>
+        <version>1.2.0</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.springframework.security.oauth</groupId>
+        <artifactId>spring-security-oauth2</artifactId>
+        <version>2.3.2.RELEASE</version>
+      </dependency>
+      <dependency>
+        <groupId>org.springframework.security</groupId>
+        <artifactId>spring-security-jwt</artifactId>
+        <version>1.0.7.RELEASE</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.springframework.security.oauth</groupId>
+      <artifactId>spring-security-oauth2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-jwt</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-common-api-endpoint</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-server-api-endpoint</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>solution-basic</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>inspector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mybatis</groupId>
+      <artifactId>mybatis</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>mysql</groupId>
+      <artifactId>mysql-connector-java</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-dbcp2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mybatis</groupId>
+      <artifactId>mybatis-spring</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-jdbc</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-aop</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context-support</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-tx</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.8</source>
+            <target>1.8</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-maven-plugin</artifactId>
+          <version>2.1.2.RELEASE</version>
+          <executions>
+            <execution>
+              <goals>
+                <goal>repackage</goal>
+              </goals>
+              <configuration>
+                <mainClass>${main.class}</mainClass>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
\ No newline at end of file
diff --git a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
new file mode 100644
index 0000000..2fdbd4c
--- /dev/null
+++ b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication;
+
+import java.util.Arrays;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
+import org.springframework.security.jwt.crypto.sign.MacSigner;
+import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+
+@Configuration
+public class AuthenticationConfiguration {
+  @Autowired
+  @Qualifier("authPasswordEncoder")
+  private PasswordEncoder passwordEncoder;
+
+  @Bean(name = "authPasswordEncoder")
+  public PasswordEncoder authPasswordEncoder() {
+    return new Pbkdf2PasswordEncoder();
+  }
+
+  @Bean(name = "authSigner")
+  public Signer authSigner() {
+    return authSignerVerifier();
+  }
+  
+  @Bean(name = "authSignerVerifier")
+  public SignerVerifier authSignerVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+
+  @Bean(name = "authUserDetailsService")
+  public UserDetailsService authUserDetailsService() {
+    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+    UserDetails uAdmin = new User("admin", passwordEncoder.encode("changeMyPassword"),
+        Arrays.asList(new SimpleGrantedAuthority("ADMIN")));
+    UserDetails uGuest = new User("guest", passwordEncoder.encode("changeMyPassword"),
+        Arrays.asList(new SimpleGrantedAuthority("GUEST")));
+    manager.createUser(uAdmin);
+    manager.createUser(uGuest);
+    return manager;
+  }
+}
diff --git a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServerMain.java b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServerMain.java
new file mode 100644
index 0000000..35b239d
--- /dev/null
+++ b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServerMain.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication;
+
+import org.apache.servicecomb.foundation.common.utils.BeanUtils;
+
+public class AuthenticationServerMain {
+  public static void main(String[] args) {
+    try {
+      BeanUtils.init();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/samples/AuthenticationServer/src/main/resources/log4j2.xml b/samples/AuthenticationServer/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..3c70391
--- /dev/null
+++ b/samples/AuthenticationServer/src/main/resources/log4j2.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!--this is sample configuration, please modify as your wish-->
+
+<configuration>
+  <Properties>
+    <Property name="log_path">./user/log/</Property>
+  </Properties>
+
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
+    </Console>
+    <RollingFile name="DailyRollingFile" fileName="${log_path}/output.log"
+      filePattern="${log_path}/zcrTest%d{yyyy-MM-dd}.log">
+      <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
+      <TimeBasedTriggeringPolicy interval="1"/>
+      <SizeBasedTriggeringPolicy size="10 MB"/>
+    </RollingFile>
+  </Appenders>
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="Console"/>
+      <AppenderRef ref="DailyRollingFile"/>
+    </Root>
+  </Loggers>
+</configuration>
\ No newline at end of file
diff --git a/samples/AuthenticationServer/src/main/resources/microservice.yaml b/samples/AuthenticationServer/src/main/resources/microservice.yaml
new file mode 100644
index 0000000..dfedc0f
--- /dev/null
+++ b/samples/AuthenticationServer/src/main/resources/microservice.yaml
@@ -0,0 +1,36 @@
+#
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# override common configurations in common module
+servicecomb-config-order: 100
+
+APPLICATION_ID: authentication-application
+service_description:
+  version: 0.0.1
+  name: authentication-server
+  environment: development
+
+servicecomb:
+  service:
+    registry:
+      address: http://localhost:30100
+      instance:
+        watch: false
+
+  rest:
+    address: 0.0.0.0:9091
diff --git a/samples/Client/pom.xml b/samples/Client/pom.xml
new file mode 100644
index 0000000..d879756
--- /dev/null
+++ b/samples/Client/pom.xml
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Licensed to the Apache Software Foundation (ASF) under one or more 
+  ~ contributor license agreements. See the NOTICE file distributed with ~ 
+  this work for additional information regarding copyright ownership. ~ The 
+  ASF licenses this file to You under the Apache License, Version 2.0 ~ (the 
+  "License"); you may not use this file except in compliance with ~ the License. 
+  You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 
+  ~ ~ Unless required by applicable law or agreed to in writing, software ~ 
+  distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT 
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the 
+  License for the specific language governing permissions and ~ limitations 
+  under the License. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-samples</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>client</artifactId>
+  <packaging>jar</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-common-api-endpoint</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-server-api-service</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.mybatis</groupId>
+        <artifactId>mybatis</artifactId>
+        <version>3.4.5</version>
+      </dependency>
+      <dependency>
+        <groupId>org.mybatis</groupId>
+        <artifactId>mybatis-spring</artifactId>
+        <version>1.3.0</version>
+      </dependency>
+      <dependency>
+        <groupId>mysql</groupId>
+        <artifactId>mysql-connector-java</artifactId>
+        <version>5.1.46</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb</groupId>
+        <artifactId>java-chassis-dependencies</artifactId>
+        <version>1.2.0</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-common-api-endpoint</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-server-api-service</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>solution-basic</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>inspector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mybatis</groupId>
+      <artifactId>mybatis</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>mysql</groupId>
+      <artifactId>mysql-connector-java</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-dbcp2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mybatis</groupId>
+      <artifactId>mybatis-spring</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-jdbc</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-aop</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context-support</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-tx</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.8</source>
+            <target>1.8</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-maven-plugin</artifactId>
+          <version>2.1.2.RELEASE</version>
+          <executions>
+            <execution>
+              <goals>
+                <goal>repackage</goal>
+              </goals>
+              <configuration>
+                <mainClass>${main.class}</mainClass>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
\ No newline at end of file
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationClientMain.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationClientMain.java
new file mode 100644
index 0000000..ce9c356
--- /dev/null
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationClientMain.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication;
+
+import org.apache.servicecomb.foundation.common.utils.BeanUtils;
+
+public class AuthenticationClientMain {
+  public static void main(String[] args) {
+    try {
+      BeanUtils.init();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
new file mode 100644
index 0000000..13bfaba
--- /dev/null
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication;
+
+import org.apache.servicecomb.authentication.jwt.JWTClaims;
+import org.apache.servicecomb.authentication.jwt.JsonParser;
+import org.apache.servicecomb.authentication.server.Token;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.security.jwt.JwtHelper;
+import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.HttpClientErrorException;
+
+@Component
+public class AuthenticationTestCase implements TestCase {
+  @Override
+  public void run() {
+    testHanlderAuth();
+    testMethodAuth();
+  }
+
+
+  private void testHanlderAuth() {
+    // get token
+    MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
+    map.add("grant_type", "password");
+    map.add("username", "admin");
+    map.add("password", "changeMyPassword");
+    HttpHeaders headers = new HttpHeaders();
+    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
+
+    Token token =
+        BootEventListener.authenticationServerTokenEndpoint.postForObject("/",
+            new HttpEntity<>(map, headers),
+            Token.class);
+    TestMgr.check("bearer", token.getToken_type());
+    TestMgr.check(true, token.getAccess_token().length() > 10);
+
+    // get resources
+    headers = new HttpHeaders();
+    headers.add("Authorization", "Bearer " + token.getAccess_token());
+    headers.setContentType(MediaType.APPLICATION_JSON);
+    String name;
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/everyoneSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/adminSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/guestOrAdminSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = null;
+    try {
+      name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/guestSayHello?name=Hi",
+          new HttpEntity<>(headers),
+          String.class);
+    } catch (HttpClientErrorException e) {
+      TestMgr.check(403, e.getStatusCode().value());
+    }
+    TestMgr.check(null, name);
+    
+    // refresh token
+    // get token
+    map = new LinkedMultiValueMap<>();
+    map.add("grant_type", "refresh_token");
+    map.add("refresh_token", token.getRefresh_token());
+    map.add("access_token", token.getAccess_token());
+    headers = new HttpHeaders();
+    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
+
+    Token tokenNew =
+        BootEventListener.authenticationServerTokenEndpoint.postForObject("/",
+            new HttpEntity<>(map, headers),
+            Token.class);
+    TestMgr.check(token.getToken_type(), tokenNew.getToken_type());
+   
+    JWTClaims claims = JsonParser.parse(JwtHelper.decode(token.getAccess_token()).getClaims(), JWTClaims.class);
+    JWTClaims newClaims = JsonParser.parse(JwtHelper.decode(tokenNew.getAccess_token()).getClaims(), JWTClaims.class);
+    TestMgr.check(claims.getJti(), newClaims.getJti());
+    TestMgr.check(claims.getIat() < newClaims.getIat(), true);
+
+    // get resources
+    headers = new HttpHeaders();
+    headers.add("Authorization", "Bearer " + tokenNew.getAccess_token());
+    headers.setContentType(MediaType.APPLICATION_JSON);
+
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/everyoneSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/adminSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/guestOrAdminSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = null;
+    try {
+      name = BootEventListener.resouceServerHandlerAuthEndpoint.postForObject("/guestSayHello?name=Hi",
+          new HttpEntity<>(headers),
+          String.class);
+    } catch (HttpClientErrorException e) {
+      TestMgr.check(403, e.getStatusCode().value());
+    }
+    TestMgr.check(null, name);
+  }
+
+
+  private void testMethodAuth() {
+    // get token
+    MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
+    map.add("grant_type", "password");
+    map.add("username", "admin");
+    map.add("password", "changeMyPassword");
+    HttpHeaders headers = new HttpHeaders();
+    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
+
+    Token token =
+        BootEventListener.authenticationServerTokenEndpoint.postForObject("/",
+            new HttpEntity<>(map, headers),
+            Token.class);
+    TestMgr.check("bearer", token.getToken_type());
+    TestMgr.check(true, token.getAccess_token().length() > 10);
+    TestMgr.check(true, token.getRefresh_token().length() > 10);
+
+    // get resources
+    headers = new HttpHeaders();
+    headers.add("Authorization", "Bearer " + token.getAccess_token());
+    headers.setContentType(MediaType.APPLICATION_JSON);
+    String name;
+    name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/everyoneSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/adminSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/guestOrAdminSayHello?name=Hi",
+        new HttpEntity<>(headers),
+        String.class);
+    TestMgr.check("Hi", name);
+
+    name = null;
+    try {
+      name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/guestSayHello?name=Hi",
+          new HttpEntity<>(headers),
+          String.class);
+    } catch (HttpClientErrorException e) {
+      TestMgr.check(403, e.getStatusCode().value());
+    }
+    TestMgr.check(null, name);
+  }
+}
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java
new file mode 100644
index 0000000..08d1bb3
--- /dev/null
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication;
+
+import org.apache.servicecomb.core.BootListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class BootEventListener implements BootListener {
+  public static GateRestTemplate authenticationServerTokenEndpoint;
+  public static GateRestTemplate gateEndpoint;
+  public static GateRestTemplate resouceServerHandlerAuthEndpoint;
+  public static GateRestTemplate resouceServerMethodAuthEndpoint;
+  
+  @Override
+  public void onBootEvent(BootEvent event) {
+    if (EventType.AFTER_REGISTRY.equals(event.getEventType())) {
+      authenticationServerTokenEndpoint =
+          GateRestTemplate.createEdgeRestTemplate("edge-service", "authentication-server", "TokenEndpoint").init();
+      gateEndpoint =
+          GateRestTemplate.createEdgeRestTemplate("edge-service", null, null).init();
+      resouceServerHandlerAuthEndpoint =
+          GateRestTemplate.createEdgeRestTemplate("edge-service", "resource-server", "HandlerAuthEndpoint").init();
+      resouceServerMethodAuthEndpoint =
+          GateRestTemplate.createEdgeRestTemplate("edge-service", "resource-server", "PreMethodAuthEndpoint").init();
+    }
+
+  }
+
+}
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/GateRestTemplate.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/GateRestTemplate.java
new file mode 100644
index 0000000..7a6709f
--- /dev/null
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/GateRestTemplate.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.authentication;
+
+import java.util.Arrays;
+
+import org.apache.servicecomb.core.definition.MicroserviceVersionMeta;
+import org.apache.servicecomb.core.definition.SchemaMeta;
+import org.apache.servicecomb.foundation.common.net.URIEndpointObject;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule;
+import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
+import org.springframework.http.converter.FormHttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+public class GateRestTemplate extends RestTemplate {
+  private final String gateName;
+
+  private final String schemaId;
+
+  private final String producerName;
+
+  private String urlPrefix;
+
+  public static GateRestTemplate createEdgeRestTemplate(String gateName, String producerName, String schemaId) {
+    return new GateRestTemplate(gateName, producerName, schemaId);
+  }
+
+
+  public GateRestTemplate(String gateName, String producerName, String schemaId) {
+    this.gateName = gateName;
+    this.producerName = producerName;
+    this.schemaId = schemaId;
+  }
+
+  public GateRestTemplate init() {
+    urlPrefix = getUrlPrefix(gateName, producerName, schemaId);
+
+    setUriTemplateHandler(new ITUriTemplateHandler(urlPrefix));
+
+    setMessageConverters(Arrays.asList(
+        new MappingJackson2HttpMessageConverter(),
+        new StringHttpMessageConverter(),
+        new FormHttpMessageConverter()));
+
+    return this;
+  }
+
+  public String getUrlPrefix() {
+    return urlPrefix;
+  }
+
+  private String getUrlPrefix(String gateName, String producerName, String schemaId) {
+    MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry()
+        .getAppManager()
+        .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(),
+            gateName,
+            DefinitionConst.VERSION_RULE_ALL);
+    MicroserviceInstance microserviceInstance = microserviceVersionRule.getInstances()
+        .values()
+        .stream()
+        .findFirst()
+        .get();
+    URIEndpointObject edgeAddress = new URIEndpointObject(microserviceInstance.getEndpoints().get(0));
+
+    String urlSchema = "http";
+    if (edgeAddress.isSslEnabled()) {
+      urlSchema = "https";
+    }
+
+    if(producerName == null) {
+      return String
+          .format("%s://%s:%d",
+              urlSchema,
+              edgeAddress.getHostOrIp(),
+              edgeAddress.getPort());
+    }
+    
+    microserviceVersionRule = RegistryUtils.getServiceRegistry()
+        .getAppManager()
+        .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(),
+            producerName,
+            DefinitionConst.VERSION_RULE_ALL);
+    MicroserviceVersionMeta microserviceVersionMeta = microserviceVersionRule.getLatestMicroserviceVersion();
+    SchemaMeta schemaMeta = microserviceVersionMeta.getMicroserviceMeta().ensureFindSchemaMeta(schemaId);
+    return String
+        .format("%s://%s:%d/api/%s%s",
+            urlSchema,
+            edgeAddress.getHostOrIp(),
+            edgeAddress.getPort(),
+            producerName,
+            schemaMeta.getSwagger().getBasePath());
+  }
+}
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/ITUriTemplateHandler.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/ITUriTemplateHandler.java
new file mode 100644
index 0000000..8308599
--- /dev/null
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/ITUriTemplateHandler.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.authentication;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.springframework.web.util.DefaultUriTemplateHandler;
+
+public class ITUriTemplateHandler extends DefaultUriTemplateHandler {
+  private String urlPrefix;
+
+  public ITUriTemplateHandler(String urlPrefix) {
+    this.urlPrefix = urlPrefix;
+  }
+
+  @Override
+  protected URI expandInternal(String uriTemplate, Object... uriVariables) {
+    return super.expandInternal(changeUrl(uriTemplate), uriVariables);
+  }
+
+  @Override
+  protected URI expandInternal(String uriTemplate, Map<String, ?> uriVariables) {
+    return super.expandInternal(changeUrl(uriTemplate), uriVariables);
+  }
+
+  private String changeUrl(String uriTemplate) {
+    return urlPrefix + uriTemplate;
+  }
+}
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestCase.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestCase.java
new file mode 100644
index 0000000..1c511d2
--- /dev/null
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestCase.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication;
+
+public interface TestCase {
+  void run();
+}
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java
new file mode 100644
index 0000000..19b0af1
--- /dev/null
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication;
+
+import java.util.List;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@RestSchema(schemaId = "TestEndpoint")
+@RequestMapping(path = "/v1/test")
+public class TestEndpoint {
+  @Autowired
+  private List<TestCase> tests;
+
+  @GetMapping(path = "/start")
+  public String start() {
+    tests.forEach(test -> test.run());
+
+    List<Throwable> errors = TestMgr.errors();
+    if (TestMgr.isSuccess()) {
+      return TestMgr.successMessage();
+    } else {
+      TestMgr.summary();
+
+      StringBuilder sb = new StringBuilder();
+      sb.append("Failed count : " + errors.size());
+      sb.append("\n");
+      errors.forEach(t -> sb.append(t.getMessage() + "\n"));
+      
+      TestMgr.reset();
+      return sb.toString();
+    }
+  }
+}
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java
new file mode 100644
index 0000000..030bb4c
--- /dev/null
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+
+public class TestMgr {
+  private static final Logger LOGGER = LoggerFactory.getLogger(TestMgr.class);
+
+  private static final List<Throwable> errorList = new ArrayList<>();
+
+  private static String msg = "";
+
+  private static AtomicLong checksCount = new AtomicLong();
+
+  public static void setMsg(String msg) {
+    TestMgr.msg = msg;
+  }
+
+  public static void setMsg(String microserviceName, String transport) {
+    TestMgr.msg = String.format("microservice=%s, transport=%s", microserviceName, transport);
+  }
+
+  public static void check(Object expect, Object real) {
+    check(expect, real, null);
+  }
+
+  public static void check(Object expect, Object real, Throwable error) {
+    checksCount.incrementAndGet();
+    if (expect == real) {
+      return;
+    }
+
+    String strExpect = String.valueOf(expect);
+    String strReal = String.valueOf(real);
+
+    if (!strExpect.equals(strReal)) {
+      Error newError = new Error(msg + " | Expect " + strExpect + ", but " + strReal);
+      if (error != null) {
+        newError.setStackTrace(error.getStackTrace());
+      }
+      errorList.add(newError);
+    }
+  }
+
+  public static void checkNotEmpty(String real) {
+    if (StringUtils.isEmpty(real)) {
+      errorList.add(new Error(msg + " | unexpected null result, method is " + getCaller()));
+    }
+  }
+
+  public static void failed(String desc, Throwable e) {
+    Error error = new Error(msg + " | " + desc + ", method is " + getCaller());
+    if (e != null) {
+      error.setStackTrace(error.getStackTrace());
+    }
+    errorList.add(error);
+  }
+
+  public static boolean isSuccess() {
+    return errorList.isEmpty();
+  }
+
+  public static void summary() {
+    if (errorList.isEmpty()) {
+      LOGGER.info("............. test finished ............");
+      return;
+    }
+
+    LOGGER.info("............. test not finished ............");
+    for (Throwable e : errorList) {
+      LOGGER.info("", e);
+    }
+  }
+
+  public static void reset() {
+    errorList.clear();
+    checksCount.set(0);
+  }
+
+  public static String successMessage() {
+    return "Success. Checkes = " + checksCount.get();
+  }
+
+  public static List<Throwable> errors() {
+    return errorList;
+  }
+
+  private static String getCaller() {
+    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+    if (stackTrace.length < 3) {
+      return null;
+    }
+    StackTraceElement stackTraceElement = stackTrace[3];
+    return stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName();
+  }
+}
diff --git a/samples/Client/src/main/resources/log4j2.xml b/samples/Client/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..3c70391
--- /dev/null
+++ b/samples/Client/src/main/resources/log4j2.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!--this is sample configuration, please modify as your wish-->
+
+<configuration>
+  <Properties>
+    <Property name="log_path">./user/log/</Property>
+  </Properties>
+
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
+    </Console>
+    <RollingFile name="DailyRollingFile" fileName="${log_path}/output.log"
+      filePattern="${log_path}/zcrTest%d{yyyy-MM-dd}.log">
+      <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
+      <TimeBasedTriggeringPolicy interval="1"/>
+      <SizeBasedTriggeringPolicy size="10 MB"/>
+    </RollingFile>
+  </Appenders>
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="Console"/>
+      <AppenderRef ref="DailyRollingFile"/>
+    </Root>
+  </Loggers>
+</configuration>
\ No newline at end of file
diff --git a/samples/Client/src/main/resources/microservice.yaml b/samples/Client/src/main/resources/microservice.yaml
new file mode 100644
index 0000000..f19ca7b
--- /dev/null
+++ b/samples/Client/src/main/resources/microservice.yaml
@@ -0,0 +1,36 @@
+#
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# override common configurations in common module
+servicecomb-config-order: 100
+
+APPLICATION_ID: authentication-application
+service_description:
+  version: 0.0.1
+  name: authentication-client
+  environment: development
+  
+servicecomb:
+  service:
+    registry:
+      address: http://localhost:30100
+      instance:
+        watch: false
+
+  rest:
+    address: 0.0.0.0:9093
diff --git a/samples/EdgeService/pom.xml b/samples/EdgeService/pom.xml
new file mode 100644
index 0000000..cb50f95
--- /dev/null
+++ b/samples/EdgeService/pom.xml
@@ -0,0 +1,111 @@
+<!-- ~ Licensed to the Apache Software Foundation (ASF) under one or more 
+  ~ contributor license agreements. See the NOTICE file distributed with ~ 
+  this work for additional information regarding copyright ownership. ~ The 
+  ASF licenses this file to You under the Apache License, Version 2.0 ~ (the 
+  "License"); you may not use this file except in compliance with ~ the License. 
+  You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 
+  ~ ~ Unless required by applicable law or agreed to in writing, software ~ 
+  distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT 
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the 
+  License for the specific language governing permissions and ~ limitations 
+  under the License. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-samples</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>edge-service</artifactId>
+  <packaging>jar</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.servicecomb</groupId>
+        <artifactId>java-chassis-dependencies</artifactId>
+        <version>1.2.0</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-edge-api-endpoint</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-server-api-service</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-edge-api-endpoint</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-server-api-service</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>solution-basic</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>inspector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>edge-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.8</source>
+            <target>1.8</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-maven-plugin</artifactId>
+          <version>2.1.2.RELEASE</version>
+          <executions>
+            <execution>
+              <goals>
+                <goal>repackage</goal>
+              </goals>
+              <configuration>
+                <mainClass>${main.class}</mainClass>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
\ No newline at end of file
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/ApiDispatcher.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/ApiDispatcher.java
new file mode 100644
index 0000000..7642268
--- /dev/null
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/ApiDispatcher.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.gateway;
+
+import java.util.Map;
+
+import org.apache.servicecomb.edge.core.AbstractEdgeDispatcher;
+import org.apache.servicecomb.edge.core.EdgeInvocation;
+
+import io.vertx.ext.web.Cookie;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
+import io.vertx.ext.web.handler.CookieHandler;
+
+//TODO: using 1.2.2+ to make it simpler
+public class ApiDispatcher extends AbstractEdgeDispatcher {
+  @Override
+  public int getOrder() {
+    return 10002;
+  }
+
+  @Override
+  public void init(Router router) {
+    String regex = "/api/([^\\/]+)/(.*)";
+    router.routeWithRegex(regex).handler(CookieHandler.create());
+    router.routeWithRegex(regex).handler(createBodyHandler());
+    router.routeWithRegex(regex).failureHandler(this::onFailure).handler(this::onRequest);
+  }
+
+  protected void onRequest(RoutingContext context) {
+    Map<String, String> pathParams = context.pathParams();
+    String microserviceName = pathParams.get("param0");
+    String path = "/" + pathParams.get("param1");
+
+    EdgeInvocation invoker = new EdgeInvocation() {
+      // Authentication. Notice: adding context must after setContext or will override by network
+      protected void setContext() throws Exception {
+        super.setContext();
+        // get session id from header and cookie for debug reasons
+        String sessionId = context.request().getHeader("session-id");
+        if (sessionId != null) {
+          this.invocation.addContext("session-id", sessionId);
+        } else {
+          Cookie sessionCookie = context.getCookie("session-id");
+          if (sessionCookie != null) {
+            this.invocation.addContext("session-id", sessionCookie.getValue());
+          }
+        }
+      }
+    };
+    invoker.init(microserviceName, context, path, httpServerFilters);
+    invoker.edgeInvoke();
+  }
+}
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
new file mode 100644
index 0000000..1e913fb
--- /dev/null
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.gateway;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.jwt.crypto.sign.MacSigner;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
+
+@Configuration
+public class AuthenticationConfiguration {
+  @Bean(name = "authSignerVerifier")
+  public SignerVerifier authSignerVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+}
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationEdgeMain.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationEdgeMain.java
new file mode 100644
index 0000000..b040342
--- /dev/null
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationEdgeMain.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.gateway;
+
+import org.apache.servicecomb.foundation.common.utils.BeanUtils;
+
+public class AuthenticationEdgeMain {
+    public static void main(String[] args) throws Exception {
+        BeanUtils.init();
+    }
+}
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/EdgeSSLCustom.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/EdgeSSLCustom.java
new file mode 100644
index 0000000..0fb1268
--- /dev/null
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/EdgeSSLCustom.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.gateway;
+
+import java.io.File;
+
+import org.apache.servicecomb.foundation.ssl.SSLCustom;
+
+public class EdgeSSLCustom extends SSLCustom {
+
+    @Override
+    public char[] decode(char[] plain) {
+        return plain;
+    }
+
+    @Override
+    public String getFullPath(String name) {
+        String fullName = System.getProperty("user.dir") + File.separator + name;
+        System.out.println(fullName);
+        return (new File(fullName)).getAbsolutePath();
+    }
+
+}
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/StaticWebpageDispatcher.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/StaticWebpageDispatcher.java
new file mode 100644
index 0000000..555ddc4
--- /dev/null
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/StaticWebpageDispatcher.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.gateway;
+
+import org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.handler.StaticHandler;
+
+public class StaticWebpageDispatcher implements VertxHttpDispatcher {
+  private static final Logger LOGGER = LoggerFactory.getLogger(StaticWebpageDispatcher.class);
+
+  private static final String WEB_ROOT = DynamicPropertyFactory.getInstance()
+      .getStringProperty("gateway.webroot", "/var/static")
+      .get();
+
+  @Override
+  public int getOrder() {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public void init(Router router) {
+    String regex = "/ui/(.*)";
+    StaticHandler webpageHandler = StaticHandler.create();
+    webpageHandler.setWebRoot(WEB_ROOT);
+    LOGGER.info("server static web page for WEB_ROOT={}", WEB_ROOT);
+    router.routeWithRegex(regex).failureHandler((context) -> {
+      LOGGER.error("", context.failure());
+    }).handler(webpageHandler);
+  }
+
+}
diff --git a/samples/EdgeService/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher b/samples/EdgeService/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
new file mode 100644
index 0000000..cf4f35b
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.servicecomb.authentication.gateway.ApiDispatcher
+org.apache.servicecomb.authentication.gateway.StaticWebpageDispatcher
\ No newline at end of file
diff --git a/samples/EdgeService/src/main/resources/log4j2.xml b/samples/EdgeService/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..b51f28e
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/log4j2.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!--this is sample configuration, please modify as your wish-->
+
+<configuration>
+  <Properties>
+    <Property name="log_path">./gateway/log/</Property>
+  </Properties>
+
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
+    </Console>
+    <RollingFile name="DailyRollingFile" fileName="${log_path}/output.log"
+      filePattern="${log_path}/zcrTest%d{yyyy-MM-dd}.log">
+      <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
+      <TimeBasedTriggeringPolicy interval="1"/>
+      <SizeBasedTriggeringPolicy size="10 MB"/>
+    </RollingFile>
+  </Appenders>
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="Console"/>
+      <AppenderRef ref="DailyRollingFile"/>
+    </Root>
+  </Loggers>
+</configuration>
\ No newline at end of file
diff --git a/samples/EdgeService/src/main/resources/microservice.yaml b/samples/EdgeService/src/main/resources/microservice.yaml
new file mode 100644
index 0000000..7531d52
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/microservice.yaml
@@ -0,0 +1,71 @@
+#
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# override common configurations in common module
+servicecomb-config-order: 100
+
+APPLICATION_ID: authentication-application
+service_description:
+  version: 0.0.1
+  name: edge-service
+  environment: development
+
+servicecomb:
+  service:
+    registry:
+      address: http://localhost:30100
+      instance:
+        watch: false
+
+  rest:
+    address: 0.0.0.0:9090
+
+  handler:
+    chain:
+      Consumer:
+        default: internalAccess,auth,qps-flowcontrol-consumer,loadbalance
+        service:
+          authentication-server: internalAccess,qps-flowcontrol-consumer,loadbalance
+          authentication-client: internalAccess,qps-flowcontrol-consumer,loadbalance
+
+  uploads:
+    directory: tmp_for_upload_gateway
+
+  samples:
+    logdir: D:\code\servicecomb-samples\porter_lightweight\gateway-service
+    
+  inspector:
+    enabled: false
+
+  executors:
+   Provider:
+     log: servicecomb.samples.executor.groupThreadPool
+     inspector: servicecomb.samples.executor.groupThreadPool
+
+# disable all servicecomb difault dispatchers, all of them are overriden
+  http:
+    dispatcher:
+      edge:
+        default:
+          enabled: false # overriden by ApiDispatcher
+      rest:
+        eanbled: false # overriden by CustomVertxRestDispatcher
+
+# StaticWebpageDispatcher checking file exists is async, and will mark request status to ended, and VertxRestDispatcher read 
+# body will print exception. 
+#gateway.webroot: /code/servicecomb-samples/porter_lightweight/gateway-service/src/main/resources
diff --git a/samples/EdgeService/src/main/resources/ui/css/style.css b/samples/EdgeService/src/main/resources/ui/css/style.css
new file mode 100644
index 0000000..5731863
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/ui/css/style.css
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.error {
+    font-family:verdana;
+    color:red;
+}
+
+.header {
+    background-color:black;
+    color:white;
+    text-align:center;
+    padding:5px;
+}
+
+.nav {
+    line-height:30px;
+    background-color:#eeeeee;
+    height:300px;
+    width:100px;
+    float:left;
+    padding:5px; 
+}
+
+.section {
+    text-align:center;
+    padding:5px;
+}
+
+.footer {
+    color:red;
+    clear:both;
+    text-align:center;
+    padding:25px; 
+}
\ No newline at end of file
diff --git a/samples/EdgeService/src/main/resources/ui/js/jquery-1.11.1.min.js b/samples/EdgeService/src/main/resources/ui/js/jquery-1.11.1.min.js
new file mode 100644
index 0000000..ab28a24
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/ui/js/jquery-1.11.1.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b [...]
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&& [...]
+},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.prop [...]
diff --git a/samples/EdgeService/src/main/resources/ui/js/login.js b/samples/EdgeService/src/main/resources/ui/js/login.js
new file mode 100644
index 0000000..c7e7c8e
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/ui/js/login.js
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function loginAction() {
+     var username = document.getElementById("username").value;
+     var password = document.getElementById("paasword").value;
+     var formData = {};
+     formData.userName = username;
+     formData.password = password;
+
+     $.ajax({
+        type: 'POST',
+        url: "/api/user-service/v1/user/login",
+        data: formData,
+        success: function (data) {
+            console.log(data);
+            setCookie("session-id", data.sessiondId, 1);
+            window.location = "/ui/upload.html";
+        },
+        error: function(data) {
+            console.log(data);
+            var error = document.getElementById("error");
+            error.textContent="Login failed";
+            error.hidden=false;
+        },
+        async: true
+    });
+}
+
+function setCookie(name,value,days) {
+    var expires = "";
+    if (days) {
+        var date = new Date();
+        date.setTime(date.getTime() + (days*24*60*60*1000));
+        expires = "; expires=" + date.toUTCString();
+    }
+    document.cookie = name + "=" + (value || "")  + expires + "; path=/";
+}
\ No newline at end of file
diff --git a/samples/EdgeService/src/main/resources/ui/js/upload.js b/samples/EdgeService/src/main/resources/ui/js/upload.js
new file mode 100644
index 0000000..7d66555
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/ui/js/upload.js
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function uploadAction() {
+     var formData = new FormData(document.getElementById("upload_form"));
+
+     $.ajax({
+        type: 'POST',
+        url: "/api/file-service/upload",
+        data: formData,
+        processData:false,
+        contentType:false,
+        success: function (data) {
+            console.log(data);
+            var error = document.getElementById("error");
+            error.textContent="Upload Successfully";
+            error.hidden=false;
+        },
+        error: function(data) {
+            console.log(data);
+            var error = document.getElementById("error");
+            error.textContent="Upload failed";
+            error.hidden=false;
+        },
+        async: true
+    });
+}
+
+function deleteAction() {
+     var fileID = document.getElementById("fileID").value;
+     $.ajax({
+        type: 'DELETE',
+        url: "/api/file-service/delete?" + $.param({ id: fileID }),
+        data: {},
+        success: function (data) {
+            console.log(data);
+            var error = document.getElementById("error");
+            error.textContent="Delete successfully";
+            error.hidden=false;
+        },
+        error: function(data) {
+            console.log(data);
+            var error = document.getElementById("error");
+            error.textContent="Delete failed";
+            error.hidden=false;
+        },
+        async: true
+    });
+}
\ No newline at end of file
diff --git a/samples/EdgeService/src/main/resources/ui/login.html b/samples/EdgeService/src/main/resources/ui/login.html
new file mode 100644
index 0000000..c8b45fb
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/ui/login.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<html>
+
+    <head>
+        <title>PORTER</title>
+        <link href="css/style.css" rel="stylesheet" type="text/css" media="all" />
+        <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>
+        <script type="text/javascript" src="js/login.js"></script>
+    </head>
+
+    <body>
+    <div class="header">
+        <h2>Login</h2>
+    </div>
+    <div class="section">
+        <form method="POST" enctype="multipart/form-data">
+            <input id="username" type="text" placeholder="Username" required="true"/>
+            <input id="paasword" type="password" placeholder="Password" required="true"/>
+            <input type="button" value="Login" onclick="loginAction()">
+        </form>
+    </div>
+    <div class="footer">
+        <p id="error" hidden="true" class="error"/>
+    </div>
+    </body>
+
+</html>
\ No newline at end of file
diff --git a/samples/EdgeService/src/main/resources/ui/upload.html b/samples/EdgeService/src/main/resources/ui/upload.html
new file mode 100644
index 0000000..bd5eeff
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/ui/upload.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<html>
+
+    <head>
+        <title>PORTER</title>
+        <link href="css/style.css" rel="stylesheet" type="text/css" media="all" />
+        <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>
+        <script type="text/javascript" src="js/upload.js"></script>
+    </head>
+
+    <body>
+    <div class="header">
+        <h2>Upload</h2>
+    </div>
+    <div class="section">
+        <form id="upload_form" method="POST">
+            <p>
+                File Name: <input type="file" name="fileName"/>
+            </p>
+            <p>
+                <input type="button" value="Upload" onclick="uploadAction()">
+            </p>
+        </form>
+    </div>
+
+    <div class="header">
+        <h2>Delete file</h2>
+    </div>
+    <div class="section">
+        <form id="delete_form" method="DELETE">
+            <p>
+                File ID: <input id="fileID" type="text"/>
+            </p>
+            <p>
+                <input type="button" value="Delete" onclick="deleteAction()">
+            </p>
+        </form>
+    </div>
+    <div class="footer">
+        <p id="error" hidden="true" class="error"/>
+    </div>
+    </body>
+
+</html>
\ No newline at end of file
diff --git a/samples/EdgeService/test/org/apache/servicecomb/authentication/test/PatternTest.java b/samples/EdgeService/test/org/apache/servicecomb/authentication/test/PatternTest.java
new file mode 100644
index 0000000..e4b2151
--- /dev/null
+++ b/samples/EdgeService/test/org/apache/servicecomb/authentication/test/PatternTest.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.test;
+
+import java.util.regex.Pattern;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class PatternTest {
+  @Test
+  public void testPattern() {
+    String regex = "(/v1/log|/inspector|/v1/auth)/(.*)";
+    Pattern p = Pattern.compile(regex);
+    Assert.assertTrue(p.matcher("/v1/log/login").matches());
+    Assert.assertTrue(p.matcher("/inspector/login").matches());
+    Assert.assertTrue(p.matcher("/v1/auth/login").matches());
+    Assert.assertTrue(!p.matcher("/api/v1/auth/login").matches());
+  }
+}
diff --git a/samples/ResourceServer/pom.xml b/samples/ResourceServer/pom.xml
new file mode 100644
index 0000000..df24f7a
--- /dev/null
+++ b/samples/ResourceServer/pom.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Licensed to the Apache Software Foundation (ASF) under one or more 
+  ~ contributor license agreements. See the NOTICE file distributed with ~ 
+  this work for additional information regarding copyright ownership. ~ The 
+  ASF licenses this file to You under the Apache License, Version 2.0 ~ (the 
+  "License"); you may not use this file except in compliance with ~ the License. 
+  You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 
+  ~ ~ Unless required by applicable law or agreed to in writing, software ~ 
+  distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT 
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the 
+  License for the specific language governing permissions and ~ limitations 
+  under the License. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+
+  <parent>
+    <groupId>org.apache.servicecomb.authentication</groupId>
+    <artifactId>authentication-samples</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>resource-server</artifactId>
+  <packaging>jar</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.servicecomb.authentication</groupId>
+        <artifactId>authentication-resource-api-endpoint</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.mybatis</groupId>
+        <artifactId>mybatis</artifactId>
+        <version>3.4.5</version>
+      </dependency>
+      <dependency>
+        <groupId>org.mybatis</groupId>
+        <artifactId>mybatis-spring</artifactId>
+        <version>1.3.0</version>
+      </dependency>
+      <dependency>
+        <groupId>mysql</groupId>
+        <artifactId>mysql-connector-java</artifactId>
+        <version>5.1.46</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb</groupId>
+        <artifactId>java-chassis-dependencies</artifactId>
+        <version>1.2.0</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-resource-api-endpoint</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>solution-basic</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>inspector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mybatis</groupId>
+      <artifactId>mybatis</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>mysql</groupId>
+      <artifactId>mysql-connector-java</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-dbcp2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mybatis</groupId>
+      <artifactId>mybatis-spring</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-jdbc</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-aop</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context-support</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-tx</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.8</source>
+            <target>1.8</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-maven-plugin</artifactId>
+          <version>2.1.2.RELEASE</version>
+          <executions>
+            <execution>
+              <goals>
+                <goal>repackage</goal>
+              </goals>
+              <configuration>
+                <mainClass>${main.class}</mainClass>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
\ No newline at end of file
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
new file mode 100644
index 0000000..712030d
--- /dev/null
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.jwt.crypto.sign.MacSigner;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
+
+@Configuration
+public class AuthenticationConfiguration {
+  @Bean(name = "authSignerVerifier")
+  public SignerVerifier authSignerVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+}
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/FileEndpoint.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/FileEndpoint.java
new file mode 100644
index 0000000..4b6a5b6
--- /dev/null
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/FileEndpoint.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestSchema(schemaId = "FileEndpoint")
+@RequestMapping(path = "/v1/file")
+public class FileEndpoint {
+    @Autowired
+    private FileStoreService fileService;
+
+    @PostMapping(path = "/upload", produces = MediaType.TEXT_PLAIN_VALUE)
+    public String uploadFile(@RequestPart(name = "fileName") MultipartFile file) {
+        return fileService.uploadFile(file);
+    }
+
+    @DeleteMapping(path = "/delete", produces = MediaType.APPLICATION_JSON_VALUE)
+    public boolean deleteFile(@RequestParam(name = "id") String id) {
+        return fileService.deleteFile(id);
+    }
+}
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/FileStoreService.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/FileStoreService.java
new file mode 100644
index 0000000..ed03665
--- /dev/null
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/FileStoreService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * file storage service, can implement using file system, OBS, etc.
+ */
+public interface FileStoreService {
+
+    public String uploadFile(MultipartFile file);
+
+    public boolean deleteFile(String id);
+
+}
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/HandlerAuthEndpoint.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/HandlerAuthEndpoint.java
new file mode 100644
index 0000000..347db46
--- /dev/null
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/HandlerAuthEndpoint.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@RestSchema(schemaId = "HandlerAuthEndpoint")
+@RequestMapping(path = "/v1/auth/handler")
+public class HandlerAuthEndpoint {
+  @PostMapping(path = "/adminSayHello")
+  public String adminSayHello(String name) {
+    return name;
+  }
+
+  @PostMapping(path = "/guestSayHello")
+  public String guestSayHello(String name) {
+    return name;
+  }
+
+  @PostMapping(path = "/guestOrAdminSayHello")
+  public String guestOrAdminSayHello(String name) {
+    return name;
+  }
+
+  @PostMapping(path = "/everyoneSayHello")
+  public String everyoneSayHello(String name) {
+    return name;
+  }
+}
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/LocalFileStoreService.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/LocalFileStoreService.java
new file mode 100644
index 0000000..d487144
--- /dev/null
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/LocalFileStoreService.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.UUID;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ *  Simple file storage implementation.
+ *  Caution: file check and other security constraints not implemented. 
+ */
+@Component
+public class LocalFileStoreService implements FileStoreService {
+    // maxmum BUFFER_SIZE * BUFFER_NUM
+    private static final int BUFFER_SIZE = 10240;
+
+    private static final File BASE_FILE = new File(".");
+
+    @Override
+    public String uploadFile(MultipartFile file) {
+        byte[] buffer = new byte[BUFFER_SIZE];
+        String fileId = UUID.randomUUID().toString();
+
+        File outFile = new File(BASE_FILE, fileId);
+        int len;
+        try (InputStream is = file.getInputStream(); OutputStream os = new FileOutputStream(outFile)) {
+            while ((len = is.read(buffer)) != -1) {
+                os.write(buffer, 0, len);
+            }
+        } catch (IOException e) {
+            return null;
+        }
+        return fileId;
+    }
+
+    @Override
+    public boolean deleteFile(String id) {
+        File outFile = new File(BASE_FILE, id);
+        return outFile.delete();
+    }
+
+}
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/MethodSecurityConfiguration.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/MethodSecurityConfiguration.java
new file mode 100644
index 0000000..58df6a9
--- /dev/null
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/MethodSecurityConfiguration.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
+
+@Configuration
+@EnableGlobalMethodSecurity(
+    prePostEnabled = true)
+public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
+  @Override
+  protected MethodSecurityExpressionHandler createExpressionHandler() {
+    DefaultMethodSecurityExpressionHandler h = (DefaultMethodSecurityExpressionHandler) super.createExpressionHandler();
+    h.setDefaultRolePrefix("");
+    return h;
+  }
+}
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/PreMethodAuthEndpoint.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/PreMethodAuthEndpoint.java
new file mode 100644
index 0000000..668f774
--- /dev/null
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/PreMethodAuthEndpoint.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@RestSchema(schemaId = "PreMethodAuthEndpoint")
+@RequestMapping(path = "/v1/auth/method")
+public class PreMethodAuthEndpoint {
+  @PostMapping(path = "/adminSayHello")
+  @PreAuthorize("hasRole('ADMIN')")
+  public String adminSayHello(String name) {
+    return name;
+  }
+
+  @PostMapping(path = "/guestSayHello")
+  @PreAuthorize("hasRole('USER')")
+  public String guestSayHello(String name) {
+    return name;
+  }
+
+  @PostMapping(path = "/guestOrAdminSayHello")
+  @PreAuthorize("hasAnyRole('USER','ADMIN')")
+  public String guestOrAdminSayHello(String name) {
+    return name;
+  }
+
+  @PostMapping(path = "/everyoneSayHello")
+  public String everyoneSayHello(String name) {
+    return name;
+  }
+}
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/ResourceServerMain.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/ResourceServerMain.java
new file mode 100644
index 0000000..1964390
--- /dev/null
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/ResourceServerMain.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.resource;
+
+import org.apache.servicecomb.foundation.common.utils.BeanUtils;
+
+public class ResourceServerMain {
+  public static void main(String[] args) {
+    try {
+      BeanUtils.init();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/samples/ResourceServer/src/main/resources/log4j2.xml b/samples/ResourceServer/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..3c70391
--- /dev/null
+++ b/samples/ResourceServer/src/main/resources/log4j2.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!--this is sample configuration, please modify as your wish-->
+
+<configuration>
+  <Properties>
+    <Property name="log_path">./user/log/</Property>
+  </Properties>
+
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
+    </Console>
+    <RollingFile name="DailyRollingFile" fileName="${log_path}/output.log"
+      filePattern="${log_path}/zcrTest%d{yyyy-MM-dd}.log">
+      <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
+      <TimeBasedTriggeringPolicy interval="1"/>
+      <SizeBasedTriggeringPolicy size="10 MB"/>
+    </RollingFile>
+  </Appenders>
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="Console"/>
+      <AppenderRef ref="DailyRollingFile"/>
+    </Root>
+  </Loggers>
+</configuration>
\ No newline at end of file
diff --git a/samples/ResourceServer/src/main/resources/microservice.yaml b/samples/ResourceServer/src/main/resources/microservice.yaml
new file mode 100644
index 0000000..69b0ffc
--- /dev/null
+++ b/samples/ResourceServer/src/main/resources/microservice.yaml
@@ -0,0 +1,51 @@
+#
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# override common configurations in common module
+servicecomb-config-order: 100
+
+APPLICATION_ID: authentication-application
+service_description:
+  version: 0.0.1
+  name: resource-server
+  environment: development
+  
+servicecomb:
+  service:
+    registry:
+      address: http://localhost:30100
+      instance:
+        watch: false
+
+  rest:
+    address: 0.0.0.0:9092
+
+  authencation:
+    access:
+      needAuth: true
+      roles:
+        HandlerAuthEndpoint:
+          adminSayHello: ADMIN
+          guestSayHello: GUEST
+          guestOrAdminSayHello: ADMIN,GUEST
+          # everyoneSayHello: all can
+
+  handler:
+    chain:
+      Provider:
+        default: qps-flowcontrol-provider,resource-auth-provider
\ No newline at end of file
diff --git a/samples/pom.xml b/samples/pom.xml
new file mode 100644
index 0000000..9bf4cac
--- /dev/null
+++ b/samples/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.servicecomb.authentication</groupId>
+  <artifactId>authentication-samples</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <modules>
+    <module>AuthenticationServer</module>
+    <module>ResourceServer</module>
+    <module>EdgeService</module>
+    <module>Client</module>
+  </modules>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.servicecomb</groupId>
+        <artifactId>java-chassis-dependencies</artifactId>
+        <version>1.2.0</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>solution-basic</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>inspector</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.8</source>
+            <target>1.8</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-maven-plugin</artifactId>
+          <version>2.1.2.RELEASE</version>
+          <executions>
+            <execution>
+              <goals>
+                <goal>repackage</goal>
+              </goals>
+              <configuration>
+                <mainClass>${main.class}</mainClass>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
\ No newline at end of file


[servicecomb-fence] 08/09: [SCB-1319]update docs and add design diagram

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit b078c954c2a4689092005abaaaf041ebae7951cc
Author: liubao <bi...@qq.com>
AuthorDate: Mon Jun 17 17:02:21 2019 +0800

    [SCB-1319]update docs and add design diagram
---
 README.md                     |   9 ++++++
 README_ZH.md                  |   9 ++++++
 docs/authentication.png       | Bin 0 -> 85676 bytes
 docs/authorization.png        | Bin 0 -> 79697 bytes
 docs/zh_CN/developersGuide.md |  72 ++++++++++++++++++++----------------------
 5 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/README.md b/README.md
index cc9dbcb..9cfeab5 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,15 @@
 
 This project is servicecomb-java-chassis security support. The main architecture is based on [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) and [OpenID Connect](https://openid.net/connect/). And provides APIs for developers based on [Spring Security](https://spring.io/projects/spring-security). Please see [developers guide](docs/zh_CN/developersGuide.md) for details.
 
+## Authentication diagram
+
+![](docs/authentication.png)
+
+
+## Authorization diagram
+
+![](docs/authorization.png)
+
 ## Project description
 
 This project contains two folders api and samples. Api folder contains components used in Authentication Server, Edge Service and Resource Server. And samples folder gives a working example showing how to use these apis. 
diff --git a/README_ZH.md b/README_ZH.md
index cf893d4..55dda1a 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -2,6 +2,15 @@
 
 本项目为servicecomb-java-chassis提供认证鉴权支持。鉴权实现的主要框架参考了[The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) 和 [OpenID Connect](https://openid.net/connect/)。项目参考[Spring Security](https://spring.io/projects/spring-security)给开发者提供了接口。请参考[开发指南](docs/zh_CN/developersGuide.md)获取详细信息。
 
+## 认证流程图
+
+![](docs/authentication.png)
+
+
+## 鉴权流程图
+
+![](docs/authorization.png)
+
 ## 项目说明
 
 项目包含了api和samples两个目录。其中api目录主要提供给Authentication Server, Edge Service and Resource Server使用的api。 samples目录是基于上诉api提供的一个开发示例。
diff --git a/docs/authentication.png b/docs/authentication.png
new file mode 100644
index 0000000..be94dfc
Binary files /dev/null and b/docs/authentication.png differ
diff --git a/docs/authorization.png b/docs/authorization.png
new file mode 100644
index 0000000..91246c0
Binary files /dev/null and b/docs/authorization.png differ
diff --git a/docs/zh_CN/developersGuide.md b/docs/zh_CN/developersGuide.md
index a681c5a..8d881ee 100644
--- a/docs/zh_CN/developersGuide.md
+++ b/docs/zh_CN/developersGuide.md
@@ -25,24 +25,23 @@ grant_type=password&username=admin&password=changeMyPassword
     "id_token": "eyJ...hbGciOiJSU...zI1NiIsImtpZCI6Ij",
     "expires_in": 600,
     "scope": null,
-    "jti": null,
     "additionalInformation": null
 }
 ```
 
   * Authentication Server 发送 Token 给 Client 。
 
-  * Client 携带  Access Token 请求 Edge Service 。
+  * Client 携带  ID Token 请求 Edge Service 。
 
 ```
 ** HTTP Request **
 
 POST http://localhost:9090/api/resource-server/v1/auth/handler/adminSayHello?name=Hi HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
-Authorization: Bearer SlAV32hkKG
+Authorization: Bearer eyJ...hbGciOiJSU...zI1NiIsImtpZCI6Ij
 ```
 
-  * Edge Service 将 Access Token 转换为对应的 ID Token , 然后将请求转发给Resource Server。
+  * Edge Service 将 ID Token 转发给Resource Server。
   * Resource Server 返回对应的资源给 Client 。 
 
 ## 开发 Authentication Server
@@ -64,36 +63,28 @@ Authentication Server 主要提供认证和授权等接口。
 
 Authentication Server 需要配置 PasswordEncoder、Signer、SignerVerifier、TokenStore、UserDetailsService 等。
 ```
-@Configuration
-public class AuthenticationConfiguration {
-  @Bean(name = "authPasswordEncoder")
+  @Bean(name = Constants.BEAN_AUTH_PASSWORD_ENCODER)
   public PasswordEncoder authPasswordEncoder() {
     return new Pbkdf2PasswordEncoder();
   }
 
-  @Bean(name = {"authSigner", "authSignatureVerifier"})
+  @Bean(name = {Constants.BEAN_AUTH_SIGNER, Constants.BEAN_AUTH_SIGNATURE_VERIFIER})
   public SignerVerifier authSignerVerifier() {
     // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
     // If using MacSigner, need to protect the shared key by properly encryption.
     return new MacSigner("Please change this key.");
   }
 
-  @Bean(name = {"authAccessTokenStore", "authRefreshTokenStore"})
-  public TokenStore sessionIDTokenStore() {
-    // Use in memory store for testing. Need to implement JDBC or Redis SessionIDTokenStore in product. 
-    return new InMemorySessionIDTokenStore();
-  }
-
-  @Bean(name = "authIDTokenStore")
-  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
-      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
-    return new JWTTokenStore(signer, signerVerifier);
+  @Bean(name = Constants.BEAN_AUTH_OPEN_ID_TOKEN_STORE)
+  public AbstractOpenIDTokenStore openIDTokenStore() {
+    // TODO: Use in memory store for testing. Need to implement JDBC or Redis SessionIDTokenStore in product. 
+    return new InMemoryOpenIDTokenStore();
   }
 
-  @Bean(name = "authUserDetailsService")
+  @Bean(name = Constants.BEAN_AUTH_USER_DETAILS_SERVICE)
   public UserDetailsService authUserDetailsService(
-      @Autowired @Qualifier("authPasswordEncoder") PasswordEncoder passwordEncoder) {
-    // Use in memory UserDetails, need to implement JDBC or others in product
+      @Autowired @Qualifier(Constants.BEAN_AUTH_PASSWORD_ENCODER) PasswordEncoder passwordEncoder) {
+    // TODO: Use in memory UserDetails, need to implement JDBC or others in product
     InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
     UserDetails uAdmin = new User("admin", passwordEncoder.encode("changeMyPassword"),
         Arrays.asList(new SimpleGrantedAuthority("ADMIN")));
@@ -103,7 +94,6 @@ public class AuthenticationConfiguration {
     manager.createUser(uGuest);
     return manager;
   }
-}
 ```
 
 * UserDetailsService
@@ -114,8 +104,8 @@ public class AuthenticationConfiguration {
 
 生成 Token 和对 Token 进行校验。Singer 和  SignatureVerifier 是配套使用的, 在 Authentication Server , 生成 Token 的时候,需要使用 Singer 。 验证 Token 的有效性 (比如查询 userDetails 等场景), 需要使用  SignatureVerifier 。 通常有两种方式进行签名和校验, 一种是基于对称秘钥的机制,比如MacSigner,即是 Singer, 也是 SignatureVerifier (SignerVerifier); 一种是基于非对称秘钥的机制, 比如 RsaSigner 和  RsaVerifier , 生成 Token 和校验 Token 的秘钥是不同的。
 
-* TokenStore
-在Authentication Server,TokenStore主要用来生成Access Token, Refresh Token和ID Token, 默认情况下, Access Token和Refresh Token都使用AbstractSessionIDTokenStore(本例子使用了InMemorySessionIDTokenStore,业务代码通常需要换为JDBC、Redis等实现), ID Token使用JWTTokenStore。 JWTTokenStore是一个无状态的会话机制,Authentication Server的任何一个实例都可以独立生成。
+* AbstractOpenIDTokenStore
+在Authentication Server,TokenStore主要用来生成Access Token, Refresh Token和ID Token, 默认情况下, Access Token和Refresh Token都使用AbstractSessionIDTokenStore(本例子使用了InMemoryOpenIDTokenStore,业务代码通常需要换为JDBC、Redis等实现), ID Token使用JWTTokenStore。 JWTTokenStore是一个无状态的会话机制,Authentication Server的任何一个实例都可以独立生成。支持Refresh Token认证的场景下,还需要实现通过Refresh Token读取其他信息的方法。
 
 * PasswordEncoder 
 
@@ -141,25 +131,25 @@ Resource Server 对 Client 的访问进行认证, 并进行权限控制。
 Resource Server 需要配置 Signer、SignatureVerifier、TokenStore 等, 对用户会话进行认证。 
 
 ```
-  @Bean(name = {"authSigner", "authSignatureVerifier"})
+  @Bean(name = {Constants.BEAN_AUTH_SIGNER, Constants.BEAN_AUTH_SIGNATURE_VERIFIER})
   public SignerVerifier authSignerVerifier() {
     // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
     // If using MacSigner, need to protect the shared key by properly encryption.
     return new MacSigner("Please change this key.");
   }
 
-  @Bean(name = "authIDTokenStore")
-  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
-      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
-    return new JWTTokenStore(signer, signerVerifier);
+  @Bean(name = Constants.BEAN_AUTH_ID_TOKEN_STORE)
+  public JWTTokenStore authIDTokenStore(@Autowired @Qualifier(Constants.BEAN_AUTH_SIGNER) Signer signer, 
+      @Autowired @Qualifier(Constants.BEAN_AUTH_SIGNATURE_VERIFIER) SignerVerifier signerVerifier) {
+    return new JWTTokenStoreImpl(signer, signerVerifier);
   }
 ```
 
 * Signer、SignatureVerifier
 对Token进行校验需要,实际上Resource Server只需要使用SignatureVerifier。
 
-* TokenStore
-默认情况下, Edge Service将ID Token传递给Resource Server,所以只需要配置authIDTokenStore。
+* JWTTokenStore
+Edge Service将ID Token传递给Resource Server,所以只需要配置JWTTokenStore。基于会话认证的场景,需要提供AbstractOpenIDTokenStore。
 
 
 * 权限配置
@@ -242,14 +232,20 @@ Edge Service 是微服务接入层。 在[单体应用微服务改造](https://b
 
 * 配置
 
-Edge Service 需要配置 EdgeTokenStore 等, 对用户会话进行认证。Edge Service 从HTTP头里面读取Access Token, 然后通过 EdgeTokenStore比对是否Access Token有效,如果有效,将对应的 ID Token传递到 Resource Server。 这里使用了 InMemoryEdgeTokenStore, 产品代码会多实例部署 Edge Service, 需要将其替换为 JDBC 或者 Redis 等实现。 
+Edge Service 需要配置 JWTTokenStore 等, 对用户会话进行认证。Edge Service 从HTTP头里面读取Id Token, 然后通过 JWTTokenStore检查ID Token是否有效,如果有效,将对应的 ID Token传递到 Resource Server。 在基于会话认证的场景下,需要使用 AbstractOpenIDTokenStore。
 
 ```
-@Configuration
-public class AuthenticationConfiguration {
-  @Bean(name = "authEdgeTokenStore")
-  public EdgeTokenStore authEdgeTokenStore() {
-    return new InMemoryEdgeTokenStore();
+  @Bean(name = {Constants.BEAN_AUTH_SIGNER, Constants.BEAN_AUTH_SIGNATURE_VERIFIER})
+  public SignerVerifier authSignerVerifier() {
+    // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
+    // If using MacSigner, need to protect the shared key by properly encryption.
+    return new MacSigner("Please change this key.");
   }
-}
+
+  @Bean(name = Constants.BEAN_AUTH_ID_TOKEN_STORE)
+  public JWTTokenStore authIDTokenStore(@Autowired @Qualifier(Constants.BEAN_AUTH_SIGNER) Signer signer, 
+      @Autowired @Qualifier(Constants.BEAN_AUTH_SIGNATURE_VERIFIER) SignerVerifier signerVerifier) {
+    return new JWTTokenStoreImpl(signer, signerVerifier);
+  }
+
 ```


[servicecomb-fence] 02/09: [SCB-1292]Add developers guide for servicecomb-fence and fix authSignatureVerifier

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit 46de410996ac63012ed1237acf21e37eae3b321f
Author: liubao <bi...@qq.com>
AuthorDate: Fri May 24 17:19:49 2019 +0800

    [SCB-1292]Add developers guide for servicecomb-fence and fix authSignatureVerifier
---
 README.md                                          | 108 +++-------
 .../server/RefreshTokenTokenGranter.java           |   6 +-
 .../authentication/edge/AuthHandler.java           |   2 +-
 .../resource/ResourceAuthHandler.java              |   2 +-
 docs/en_US/developersGuide.md                      |   1 +
 docs/zh_CN/developersGuide.md                      | 219 +++++++++++++++++++++
 .../AuthenticationConfiguration.java               |   9 +-
 samples/EdgeService/pom.xml                        |   4 -
 .../gateway/AuthenticationConfiguration.java       |   4 +-
 .../resource/AuthenticationConfiguration.java      |   6 +-
 10 files changed, 258 insertions(+), 103 deletions(-)

diff --git a/README.md b/README.md
index c91d67e..8befb72 100644
--- a/README.md
+++ b/README.md
@@ -1,110 +1,54 @@
-This project demonstrates authentications and authorizations based on JWT/OAuth2. Projct names follow OAuth2 architecture. 
+# English
 
-## Implementations
+This project is servicecomb-java-chassis security support. The main architecture is based on [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) and [OpenID Connect](https://openid.net/connect/). And provides APIs for developers based on [Spring Security](https://spring.io/projects/spring-security). Please see [developers guide](docs/en_US/developersGuide.md) for details.
 
-This project uses spring security API and mainly designed for ServiceComb architecture.
+## Project description
 
-* User Management
+This project contains two folders api and samples. Api folder contains components used in Authentication Server, Edge Service and Resource Server. And samples folder gives a working example showing how to use these apis. 
 
-  1. UserDetailsService: load users information
-  2. UserDetails: User information
-  3. GrantedAuthority: authorities
-  4. PasswordEncoder: encode or verify user password
+* Build and run
 
-## Project
-
-* AuthenticationServer
-
-Authentication server implementation. Provides APIs to login, and query roles, etc. 
-
-
-* Gateway
-
-Check if users are authenticated and dispatch HTTP request.
-
-* Client
-
-Demonstrates how client uses this project. Integration tests are provided. 
-
-
-* Api
-Reusable part. 
+```
+cd samples
+mvn clean install
+```
 
-* For testing
+After build, the Authentication Server, Resource Server, Edge Service and Testing Client runnable jar are generated, start and run the four services.
 
-Run AuthenticationServer、Gateway、Client、ResourceServer and call
+* Run tests
 
+After services are started, try
 ```
 http://localhost:9093/v1/test/start
 ```
 
-see AuthenticationTestCase for details.
-
-
-本项目提供认证鉴权服务的实现,主要提供了基于角色的权限管理,和基于JWT的微服务授权模式。微服务的命名参考了OAuth2协议里面的命名方式。可以参考[OAuth2.0原理和验证流程分析](https://www.jianshu.com/p/d74ce6ca0c33)对于OAuth2认证过程的介绍,本项目的认证过程非常类似OAuth2的密码模式。
+see AuthenticationTestCase for testing details.
 
-项目的目标是提供一个商业可用的鉴权实现,对于项目代码实现的问题可以提交issue,本项目也接纳PR,共同完善。
 
+# 中文
+本项目为servicecomb-java-chassis提供认证鉴权支持。鉴权实现的主要框架参考了[The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) 和 [OpenID Connect](https://openid.net/connect/)。项目参考[Spring Security](https://spring.io/projects/spring-security)给开发者提供了接口。请参考[开发指南](docs/zh_CN/developersGuide.md)获取详细信息。
 
+## 项目说明
 
-## 实现说明
+项目包含了api和samples两个目录。其中api目录主要提供给Authentication Server, Edge Service and Resource Server使用的api。 samples目录是基于上诉api提供的一个开发示例。
 
-* 用户管理
-用户管理采用了org.springframework.security.core.userdetails的模型,包括:
-  1. UserDetailsService:加载用户信息。
-  2. UserDetails:用户信息。
-  3. GrantedAuthority:角色信息。
-  4. PasswordEncoder:用户密码加密和匹配。
-  
-  
-## 项目结构介绍
+* 编译和运行
 
-* AuthenticationServer
 
-认证鉴权服务。提供用户管理、角色管理。并提供登录认证、权限查询等接口。鉴权服务及相关API是核心交付件,也是能够被重用的部分。开发者可以基于这个项目开发认证鉴权服务。
-
-* Gateway
-提供请求拦截,校验用户是否已经经过认证。一方面演示网关如何和配套鉴权服务完成开发,本项目也是自动化测试的组成部分。
-
-* Client
-Client模拟的是使用使用者。一方面演示客户端如何获取Token,本项目也是自动化测试的组成部分。
-
-* ResourceServer
-ResourceServer模拟的是业务服务。一方面演示业务服务如何进行权限配置,本项目也是自动化测试的组成部分。
-
-* Api
-认证鉴权提取的公共功能,作为复用单元。目前项目处于初始阶段,很多复用代码分散在其他项目中。
+```
+cd samples
+mvn clean install
+```
 
+编译完成后,会生成Authentication Server, Resource Server, Edge Service and Testing Client可执行jar包,运行这四个服务。
 
-* 测试介绍
+* 运行测试用例
 
-本项目实现了微服务架构的自动化测试。启动AuthenticationServer、Gateway、Client、ResourceServer后,可以提供
+当四个服务都运行起来后,访问:
 
 ```
 http://localhost:9093/v1/test/start
 ```
-触发测试用例的执行。 所有的测试用例放到Client微服务里面, 这个微服务实现了简单的测试框架帮助书写测试用例,对测试结果进行检查等功能。 
-
-测试项目同时展示了这个项目的功能,比如: AuthenticationTestCase 的测试逻辑展示了基本的认证功能,从登陆,到接口的权限检查。 
-
-# TODO LIST
-1. provide TLS for authentication server & edge service
-2. grant scope for INTERNAL access & EXTERNAL access 
-3. access token support: a. use access token to get optional scope or roles token. 这个可以解决角色过多的时候, token过大的一些问题
-4. 实现注销逻辑(会话管理)
-5. 支持分层的角色机制
-
-       ROLE_LEVEL1
-        /       \
-   ROLE_LEVEL2  ROLE_LEVEL2
-
- TOKEN里面只返回ROLE_LEVEL1,设置为ROLE_LEVEL2访问的操作,也可以访问。
-
-6. REFRESH_TOKEN可以用来实现申请不同SCOPE的TOKEN。 
-7. 设计目标:无状态。认证服务器和资源服务器均可以多实例部署,每个实例之间不共享状态。在实现很多功能的时候,都遵循这个约束。包括通过refresh token获取新的access token的时候。遵循这个约束,意味着请求需要同时传递refresh token和access token。 
-8, 重新设计TOKEN(代码重构、支持会话管理),支持OpenID Connect。
-
-OAUTH的不好的地方:TOKEN在有效期内,容易被利用,无法注销;TOKEN过期后,必须重新认证,和用户是否在一直操作无关,体验不好,虽然可以通过refresh_token获取新的token提升体验,但是refresh_token有效期如果设置的太长,会降低安全性。Token在有效期内,如果修改了权限等信息,无法及时感知,需要重新登录。
-OAUTH的好的地方:TOKEN签发、认证都可以由微服务实例独自完成,不需要共用的数据存储,比如数据库、Redis等,效率更高,弹性扩容。
 
+可以通过查看AuthenticationTestCase了解测试用例的详情。
 
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
index ffbf9c5..7a41e90 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
@@ -25,8 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.jwt.Jwt;
 import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
 import org.springframework.security.jwt.crypto.sign.Signer;
-import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 import org.springframework.stereotype.Component;
 
 import com.netflix.config.DynamicPropertyFactory;
@@ -34,8 +34,8 @@ import com.netflix.config.DynamicPropertyFactory;
 @Component(value = "fefreshTokenTokenGranter")
 public class RefreshTokenTokenGranter implements TokenGranter {
   @Autowired
-  @Qualifier("authSignerVerifier")
-  private SignerVerifier signerVerifier;
+  @Qualifier("authSignatureVerifier")
+  private SignatureVerifier signerVerifier;
 
   @Autowired
   @Qualifier("authSigner")
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
index 40ef32d..abf4587 100644
--- a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
+++ b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
@@ -38,7 +38,7 @@ public class AuthHandler implements Handler {
     }
     Jwt jwt = JwtHelper.decode(token);
     try {
-      jwt.verifySignature(BeanUtils.getBean("authSignerVerifier"));
+      jwt.verifySignature(BeanUtils.getBean("authSignatureVerifier"));
     } catch (InvalidSignatureException e) {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
index 1d8e32b..68c6960 100644
--- a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
@@ -59,7 +59,7 @@ public class ResourceAuthHandler implements Handler {
     Jwt jwt = JwtHelper.decode(token);
     JWTClaims claims;
     try {
-      jwt.verifySignature(BeanUtils.getBean("authSignerVerifier"));
+      jwt.verifySignature(BeanUtils.getBean("authSignatureVerifier"));
       claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
       // TODO: verify claims.
     } catch (Exception e) {
diff --git a/docs/en_US/developersGuide.md b/docs/en_US/developersGuide.md
new file mode 100644
index 0000000..f87f5c1
--- /dev/null
+++ b/docs/en_US/developersGuide.md
@@ -0,0 +1 @@
+# TODO
\ No newline at end of file
diff --git a/docs/zh_CN/developersGuide.md b/docs/zh_CN/developersGuide.md
new file mode 100644
index 0000000..013f98f
--- /dev/null
+++ b/docs/zh_CN/developersGuide.md
@@ -0,0 +1,219 @@
+# servicecomb-fence 开发指南
+
+开发者可以使用 servicecomb-fence 给 servicecomb-java-chassis 微服务项目增加基于 OpenID Connect 的认证鉴权能力。
+
+## 认证鉴权流程介绍
+
+### 密码模式
+
+  * Client 输入用户名密码向 Authentication Server 请求 Token。
+
+```
+** HTTP Request **
+
+POST http://localhost:9090/api/authentication-server/v1/oauth/token HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=password&username=admin&password=changeMyPassword
+```
+
+  * Authentication Server 发送 Token 给 Client 。
+
+  * Client 携带 Token 请求 Resource Server 。
+
+```
+** HTTP Request **
+
+POST http://localhost:9090/api/resource-server/v1/auth/handler/adminSayHello?name=Hi HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW
+```
+
+  * Resource Server 返回对应的资源给 Client 。 
+
+## 开发 Authentication Server
+
+Authentication Server 主要提供认证和授权等接口。  
+
+* 配置依赖
+
+项目中引入
+
+```
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-server-api-endpoint</artifactId>
+    </dependency>
+```
+
+* 配置
+
+Authentication Server 需要配置 PasswordEncoder、Signer、SignerVerifier、UserDetailsService 等。这些对象和 Spring Security的概念一样。
+```
+@Configuration
+public class AuthenticationConfiguration {
+  @Autowired
+  @Qualifier("authPasswordEncoder")
+  private PasswordEncoder passwordEncoder;
+
+  @Bean(name = "authPasswordEncoder")
+  public PasswordEncoder authPasswordEncoder() {
+    return new Pbkdf2PasswordEncoder();
+  }
+
+  @Bean(name = "authSigner")
+  public Signer authSigner() {
+    return authSignerVerifier();
+  }
+  
+  @Bean(name = "authSignerVerifier")
+  public SignerVerifier authSignerVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+
+  @Bean(name = "authUserDetailsService")
+  public UserDetailsService authUserDetailsService() {
+    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+    UserDetails uAdmin = new User("admin", passwordEncoder.encode("changeMyPassword"),
+        Arrays.asList(new SimpleGrantedAuthority("ADMIN")));
+    UserDetails uGuest = new User("guest", passwordEncoder.encode("changeMyPassword"),
+        Arrays.asList(new SimpleGrantedAuthority("GUEST")));
+    manager.createUser(uAdmin);
+    manager.createUser(uGuest);
+    return manager;
+  }
+}
+```
+
+* UserDetailsService
+
+获取用户详情,包括用户名称、角色等信息。包括 InMemoryUserDetailsManager 、 JdbcUserDetailsManager 等实现。示例项目使用了InMemoryUserDetailsManager , 它不会持久化, 正式项目需要使用 JdbcUserDetailsManager 等。
+
+* Signer 和  SignatureVerifier 
+
+生成 Token 和对 Token 进行校验。Singer 和  SignatureVerifier 是配套使用的, 在 Authentication Server , 生成 Token 的时候,需要使用 Singer 。 验证 Token 的有效性 (比如查询 userDetails 等场景), 需要使用  SignatureVerifier 。 通常有两种方式进行签名和校验, 一种是基于对称秘钥的机制,比如MacSigner,即是 Singer, 也是 SignatureVerifier (SignerVerifier); 一种是基于非对称秘钥的机制, 比如 RsaSigner 和  RsaVerifier , 生成 Token 和校验 Token 的秘钥是不同的。
+
+* PasswordEncoder 
+
+从 UserDetailsService 校验用户密码的时候需要使用。 开发者需要在加密性能和保密程度方面选择合适的算法。 常用的有 Pbkdf2PasswordEncoder , 它可以设置迭代次数,能够更好的保护密码不被暴力破解。 
+
+## 开发 Resource Server
+
+Resource Server 对 Client 的访问进行认证, 并进行权限控制。 
+
+* 配置依赖
+
+项目中引入
+
+```
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-resource-api-endpoint</artifactId>
+    </dependency>
+```
+
+* 配置
+
+Resource Server 需要配置 SignatureVerifier 等, 对用户会话进行认证。 
+```
+@Configuration
+public class AuthenticationConfiguration {
+  @Bean(name = "authSignatureVerifier")
+  public SignerVerifier authSignatureVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+}
+```
+
+* 权限配置
+
+fence 提供了两种方式进行权限配置。 一种是基于配置文件的,一种是基于 Annotation 。
+
+基于文件的配置, 在 microservice.yaml 中可以配置每个方法的访问权限。 
+
+```
+servicecomb:
+  authencation:
+    access:
+      needAuth: true
+      roles:
+        HandlerAuthEndpoint:
+          adminSayHello: ADMIN
+          guestSayHello: GUEST
+          guestOrAdminSayHello: ADMIN,GUEST
+          # everyoneSayHello: all can
+```
+
+还可以统一配置Schema
+
+```
+servicecomb:
+  authencation:
+    access:
+      needAuth: true
+      roles:
+        HandlerAuthEndpoint: ADMIN
+```
+
+或者所有
+
+```
+servicecomb:
+  authencation:
+    access:
+      needAuth: true
+      roles: ADMIN
+```
+
+基于 Annotation , 可以使用 PreAuthorize 标签
+
+```
+@PreAuthorize("hasRole('ADMIN')")
+```
+
+Annotation 支持默认没有启用, 可以通过 EnableGlobalMethodSecurity 标签启用。 
+
+```
+@Configuration
+@EnableGlobalMethodSecurity(
+    prePostEnabled = true)
+public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
+  @Override
+  protected MethodSecurityExpressionHandler createExpressionHandler() {
+    DefaultMethodSecurityExpressionHandler h = (DefaultMethodSecurityExpressionHandler) super.createExpressionHandler();
+    h.setDefaultRolePrefix("");
+    return h;
+  }
+}
+```
+
+
+## 开发 Edge Service
+
+Edge Service 是微服务接入层。 在[单体应用微服务改造](https://bbs.huaweicloud.com/blogs/17ad483f325f11e9bd5a7ca23e93a891)中介绍了基于网关的弹性架构, 这种架构对于微服务持续演进具有重要意义, 因此建议开发者都按照这个[基础架构](https://bbs.huaweicloud.com/blogs/8bb2c3b8366c11e9bd5a7ca23e93a891)搭建微服务。接入层在认证鉴权的功能包括透传 Authentication Server的请求, 将HTTP消息转化为ServiceComb-java-chassis友好的消息格式,对Token进行认证,控制内部接口和外部接口的隔离等功能。 
+
+* 配置依赖
+
+项目中引入
+
+```
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-edge-api-endpoint</artifactId>
+    </dependency>
+```
+
+* 配置
+
+Edge Service 需要配置 SignatureVerifier 等, 对用户会话进行认证。 
+```
+
+@Configuration
+public class AuthenticationConfiguration {
+  @Bean(name = "authSignatureVerifier")
+  public SignerVerifier authSignatureVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+}
+
+```
diff --git a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
index 2fdbd4c..b70273f 100644
--- a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
+++ b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
@@ -30,7 +30,6 @@ import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.Signer;
 import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
 
@@ -45,12 +44,8 @@ public class AuthenticationConfiguration {
     return new Pbkdf2PasswordEncoder();
   }
 
-  @Bean(name = "authSigner")
-  public Signer authSigner() {
-    return authSignerVerifier();
-  }
-  
-  @Bean(name = "authSignerVerifier")
+  // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
+  @Bean(name = {"authSigner", "authSignatureVerifier" })
   public SignerVerifier authSignerVerifier() {
     return new MacSigner("Please change this key.");
   }
diff --git a/samples/EdgeService/pom.xml b/samples/EdgeService/pom.xml
index cb50f95..e0ecf5c 100644
--- a/samples/EdgeService/pom.xml
+++ b/samples/EdgeService/pom.xml
@@ -56,10 +56,6 @@
       <artifactId>authentication-edge-api-endpoint</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.servicecomb.authentication</groupId>
-      <artifactId>authentication-server-api-service</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.servicecomb</groupId>
       <artifactId>solution-basic</artifactId>
     </dependency>
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
index 1e913fb..510d821 100644
--- a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
@@ -24,8 +24,8 @@ import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSignerVerifier")
-  public SignerVerifier authSignerVerifier() {
+  @Bean(name = "authSignatureVerifier")
+  public SignerVerifier authSignatureVerifier() {
     return new MacSigner("Please change this key.");
   }
 }
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
index 712030d..2074321 100644
--- a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
@@ -20,12 +20,12 @@ package org.apache.servicecomb.authentication.resource;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.SignerVerifier;
+import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSignerVerifier")
-  public SignerVerifier authSignerVerifier() {
+  @Bean(name = "authSignatureVerifier")
+  public SignatureVerifier authSignatureVerifier() {
     return new MacSigner("Please change this key.");
   }
 }


[servicecomb-fence] 06/09: [SCB-1293]update readme and seperate english and zh_cn

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit 3d0ee93eb3730ef5133af6436613b5ee543535c6
Author: liubao <bi...@qq.com>
AuthorDate: Fri May 31 17:38:47 2019 +0800

    [SCB-1293]update readme and seperate english and zh_cn
---
 README.md                 | 36 ++++++------------------------------
 README.md => README_ZH.md | 32 +++++---------------------------
 2 files changed, 11 insertions(+), 57 deletions(-)

diff --git a/README.md b/README.md
index 8befb72..cc9dbcb 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# English
+# Fence | [中文](README_ZH.md) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Gitter](https://img.shields.io/badge/ServiceComb-Gitter-ff69b4.svg)](https://gitter.im/ServiceCombUsers/Lobby)
 
-This project is servicecomb-java-chassis security support. The main architecture is based on [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) and [OpenID Connect](https://openid.net/connect/). And provides APIs for developers based on [Spring Security](https://spring.io/projects/spring-security). Please see [developers guide](docs/en_US/developersGuide.md) for details.
+This project is servicecomb-java-chassis security support. The main architecture is based on [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) and [OpenID Connect](https://openid.net/connect/). And provides APIs for developers based on [Spring Security](https://spring.io/projects/spring-security). Please see [developers guide](docs/zh_CN/developersGuide.md) for details.
 
 ## Project description
 
@@ -24,31 +24,7 @@ http://localhost:9093/v1/test/start
 
 see AuthenticationTestCase for testing details.
 
-
-# 中文
-本项目为servicecomb-java-chassis提供认证鉴权支持。鉴权实现的主要框架参考了[The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) 和 [OpenID Connect](https://openid.net/connect/)。项目参考[Spring Security](https://spring.io/projects/spring-security)给开发者提供了接口。请参考[开发指南](docs/zh_CN/developersGuide.md)获取详细信息。
-
-## 项目说明
-
-项目包含了api和samples两个目录。其中api目录主要提供给Authentication Server, Edge Service and Resource Server使用的api。 samples目录是基于上诉api提供的一个开发示例。
-
-* 编译和运行
-
-
-```
-cd samples
-mvn clean install
-```
-
-编译完成后,会生成Authentication Server, Resource Server, Edge Service and Testing Client可执行jar包,运行这四个服务。
-
-* 运行测试用例
-
-当四个服务都运行起来后,访问:
-
-```
-http://localhost:9093/v1/test/start
-```
-
-可以通过查看AuthenticationTestCase了解测试用例的详情。
-
+## Contact Us
+* [issues](https://issues.apache.org/jira/browse/SCB)
+* [gitter](https://gitter.im/ServiceCombUsers/Lobby)
+* mailing list: [subscribe](mailto:dev-subscribe@servicecomb.apache.org) [view](https://lists.apache.org/list.html?dev@servicecomb.apache.org)
diff --git a/README.md b/README_ZH.md
similarity index 50%
copy from README.md
copy to README_ZH.md
index 8befb72..cf893d4 100644
--- a/README.md
+++ b/README_ZH.md
@@ -1,31 +1,5 @@
-# English
+# Fence | [English](README.md) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Gitter](https://img.shields.io/badge/ServiceComb-Gitter-ff69b4.svg)](https://gitter.im/ServiceCombUsers/Lobby)
 
-This project is servicecomb-java-chassis security support. The main architecture is based on [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) and [OpenID Connect](https://openid.net/connect/). And provides APIs for developers based on [Spring Security](https://spring.io/projects/spring-security). Please see [developers guide](docs/en_US/developersGuide.md) for details.
-
-## Project description
-
-This project contains two folders api and samples. Api folder contains components used in Authentication Server, Edge Service and Resource Server. And samples folder gives a working example showing how to use these apis. 
-
-* Build and run
-
-```
-cd samples
-mvn clean install
-```
-
-After build, the Authentication Server, Resource Server, Edge Service and Testing Client runnable jar are generated, start and run the four services.
-
-* Run tests
-
-After services are started, try
-```
-http://localhost:9093/v1/test/start
-```
-
-see AuthenticationTestCase for testing details.
-
-
-# 中文
 本项目为servicecomb-java-chassis提供认证鉴权支持。鉴权实现的主要框架参考了[The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) 和 [OpenID Connect](https://openid.net/connect/)。项目参考[Spring Security](https://spring.io/projects/spring-security)给开发者提供了接口。请参考[开发指南](docs/zh_CN/developersGuide.md)获取详细信息。
 
 ## 项目说明
@@ -52,3 +26,7 @@ http://localhost:9093/v1/test/start
 
 可以通过查看AuthenticationTestCase了解测试用例的详情。
 
+## 联系我们
+* [提交issues](https://issues.apache.org/jira/browse/SCB)
+* [gitter聊天室](https://gitter.im/ServiceCombUsers/Lobby)
+* 邮件列表: [订阅](mailto:dev-subscribe@servicecomb.apache.org) [浏览](https://lists.apache.org/list.html?dev@servicecomb.apache.org)


[servicecomb-fence] 09/09: Merge pull request #3 from liubao68/master

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit fd6e71c00a105a8994e4a98ddb27cb11454d8c5a
Merge: 3d0ee93 b078c95
Author: bao liu <bi...@qq.com>
AuthorDate: Tue Jun 18 20:39:41 2019 +0800

    Merge pull request #3 from liubao68/master
    
    [SCB-1319]refactor code to better satisfy session token & jwt token a…

 README.md                                          |   9 ++
 README_ZH.md                                       |   9 ++
 .../server/PasswordTokenGranter.java               |  38 +++-----
 .../server/RefreshTokenTokenGranter.java           |  36 ++-----
 .../authentication/server/TokenResponse.java       |  32 +++---
 .../authentication/token/TokenConfiguration.java   |  30 +++---
 .../token/AbstractOpenIDTokenStore.java            |  52 ++++++++++
 .../token/InMemoryOpenIDTokenStore.java            |  51 ++++++++++
 .../token/InMemorySessionIDTokenStore.java         |  42 --------
 .../servicecomb/authentication/token/JWTToken.java |  65 +------------
 .../token/{JWTToken.java => JWTTokenImpl.java}     |   8 +-
 .../authentication/token/JWTTokenStore.java        |  53 +---------
 .../{JWTTokenStore.java => JWTTokenStoreImpl.java} |  22 ++---
 .../authentication/token/OpenIDToken.java          | 108 +++++++++++++++++++++
 .../{TokenStore.java => OpenIDTokenStore.java}     |  13 ++-
 ...tSessionIDTokenStore.java => SessionToken.java} |   2 +-
 .../{SessionIDToken.java => SessionTokenImpl.java} |  15 +--
 .../{TokenStore.java => SessionTokenStore.java}    |  11 ++-
 .../servicecomb/authentication/token/Token.java    |   2 +-
 .../authentication/token/TokenStore.java           |   6 +-
 .../servicecomb/authentication/util/Constants.java |  27 ++++++
 .../authentication/edge/AuthHandler.java           |  41 +++++---
 .../authentication/edge/AuthenticationFilter.java  |   6 +-
 ...re.java => DumyEdgeTokenResponseProcessor.java} |  10 +-
 ...yEdgeTokenStore.java => EdgeConfiguration.java} |  26 ++---
 ...nStore.java => EdgeTokenResponseProcessor.java} |   6 +-
 .../authentication/edge/TokenEndpoint.java         |   8 +-
 .../resource/ResourceAuthHandler.java              |  18 ++--
 docs/authentication.png                            | Bin 0 -> 85676 bytes
 docs/authorization.png                             | Bin 0 -> 79697 bytes
 docs/zh_CN/developersGuide.md                      |  83 +++++++---------
 .../AuthenticationConfiguration.java               |  32 +++---
 samples/Client/pom.xml                             |   9 --
 .../authentication/AuthenticationTestCase.java     |  29 +++---
 .../servicecomb/authentication/TestEndpoint.java   |  14 ++-
 .../apache/servicecomb/authentication/TestMgr.java |   4 +-
 .../gateway/AuthenticationConfiguration.java       |  25 ++++-
 .../resource/AuthenticationConfiguration.java      |  14 +--
 38 files changed, 523 insertions(+), 433 deletions(-)


[servicecomb-fence] 07/09: [SCB-1319]refactor code to better satisfy session token & jwt token authentication

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit d16bba4634bd4c548424b45d994cb799e3949f3b
Author: liubao <bi...@qq.com>
AuthorDate: Mon Jun 17 15:08:29 2019 +0800

    [SCB-1319]refactor code to better satisfy session token & jwt token authentication
---
 .../server/PasswordTokenGranter.java               |  38 +++-----
 .../server/RefreshTokenTokenGranter.java           |  36 ++-----
 .../authentication/server/TokenResponse.java       |  32 +++---
 .../authentication/token/TokenConfiguration.java   |  30 +++---
 .../token/AbstractOpenIDTokenStore.java            |  52 ++++++++++
 .../token/InMemoryOpenIDTokenStore.java            |  51 ++++++++++
 .../token/InMemorySessionIDTokenStore.java         |  42 --------
 .../servicecomb/authentication/token/JWTToken.java |  65 +------------
 .../token/{JWTToken.java => JWTTokenImpl.java}     |   8 +-
 .../authentication/token/JWTTokenStore.java        |  53 +---------
 .../{JWTTokenStore.java => JWTTokenStoreImpl.java} |  22 ++---
 .../authentication/token/OpenIDToken.java          | 108 +++++++++++++++++++++
 .../token/{Token.java => OpenIDTokenStore.java}    |  19 ++--
 ...tSessionIDTokenStore.java => SessionToken.java} |   2 +-
 .../{SessionIDToken.java => SessionTokenImpl.java} |  15 +--
 .../{TokenStore.java => SessionTokenStore.java}    |  11 ++-
 .../servicecomb/authentication/token/Token.java    |   2 +-
 .../authentication/token/TokenStore.java           |   6 +-
 .../servicecomb/authentication/util/Constants.java |  27 ++++++
 .../authentication/edge/AuthHandler.java           |  41 +++++---
 .../authentication/edge/AuthenticationFilter.java  |   6 +-
 ...re.java => DumyEdgeTokenResponseProcessor.java} |  10 +-
 ...yEdgeTokenStore.java => EdgeConfiguration.java} |  26 ++---
 ...nStore.java => EdgeTokenResponseProcessor.java} |   6 +-
 .../authentication/edge/TokenEndpoint.java         |   8 +-
 .../resource/ResourceAuthHandler.java              |  18 ++--
 docs/zh_CN/developersGuide.md                      |  13 +--
 .../AuthenticationConfiguration.java               |  32 +++---
 samples/Client/pom.xml                             |   9 --
 .../authentication/AuthenticationTestCase.java     |  29 +++---
 .../servicecomb/authentication/TestEndpoint.java   |  14 ++-
 .../apache/servicecomb/authentication/TestMgr.java |   4 +-
 .../gateway/AuthenticationConfiguration.java       |  25 ++++-
 .../resource/AuthenticationConfiguration.java      |  14 +--
 34 files changed, 470 insertions(+), 404 deletions(-)

diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
index a1538ff..6f893cd 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
@@ -19,7 +19,9 @@ package org.apache.servicecomb.authentication.server;
 
 import java.util.Map;
 
-import org.apache.servicecomb.authentication.token.TokenStore;
+import org.apache.servicecomb.authentication.token.AbstractOpenIDTokenStore;
+import org.apache.servicecomb.authentication.token.OpenIDToken;
+import org.apache.servicecomb.authentication.util.Constants;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.core.userdetails.UserDetails;
@@ -29,27 +31,19 @@ import org.springframework.stereotype.Component;
 
 import com.netflix.config.DynamicPropertyFactory;
 
-@Component(value = "passwordTokenGranter")
+@Component
 public class PasswordTokenGranter implements TokenGranter {
   @Autowired
-  @Qualifier("authUserDetailsService")
+  @Qualifier(Constants.BEAN_AUTH_USER_DETAILS_SERVICE)
   private UserDetailsService userDetailsService;
 
   @Autowired
-  @Qualifier("authPasswordEncoder")
+  @Qualifier(Constants.BEAN_AUTH_PASSWORD_ENCODER)
   private PasswordEncoder passwordEncoder;
 
   @Autowired
-  @Qualifier("authAccessTokenStore")
-  private TokenStore accessTokenStore;
-
-  @Autowired
-  @Qualifier("authRefreshTokenStore")
-  private TokenStore refreshTokenStore;
-
-  @Autowired
-  @Qualifier("authIDTokenStore")
-  private TokenStore idTokenStore;
+  @Qualifier(Constants.BEAN_AUTH_OPEN_ID_TOKEN_STORE)
+  private AbstractOpenIDTokenStore openIDTokenStore;
 
   @Override
   public TokenResponse grant(Map<String, String> parameters) {
@@ -58,17 +52,9 @@ public class PasswordTokenGranter implements TokenGranter {
 
     UserDetails userDetails = userDetailsService.loadUserByUsername(username);
     if (passwordEncoder.matches(password, userDetails.getPassword())) {
-      TokenResponse token = new TokenResponse();
-      token.setAccess_token(accessTokenStore.createToken(userDetails).getValue());
-      token.setRefresh_token(refreshTokenStore.createToken(userDetails).getValue());
-      token.setId_token(idTokenStore.createToken(userDetails).getValue());
-
-      //TODO add parameters.
-      token.setScope(null);
-      token.setExpires_in(10 * 60);
-      token.setToken_type("bearer");
-
-      return token;
+      OpenIDToken openIDToken = openIDTokenStore.createToken(userDetails);
+      openIDTokenStore.saveToken(openIDToken);
+      return TokenResponse.fromOpenIDToken(openIDToken);
     } else {
       return null;
     }
@@ -82,7 +68,7 @@ public class PasswordTokenGranter implements TokenGranter {
   @Override
   public boolean enabled() {
     return DynamicPropertyFactory.getInstance()
-        .getBooleanProperty("servicecomb.authentication.granter.password.enabled", true)
+        .getBooleanProperty(Constants.CONFIG_GRANTER_PASSWORD_ENABLED, true)
         .get();
   }
 
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
index 6980287..4b0f93f 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
@@ -19,8 +19,10 @@ package org.apache.servicecomb.authentication.server;
 
 import java.util.Map;
 
+import org.apache.servicecomb.authentication.token.AbstractOpenIDTokenStore;
+import org.apache.servicecomb.authentication.token.OpenIDToken;
 import org.apache.servicecomb.authentication.token.Token;
-import org.apache.servicecomb.authentication.token.TokenStore;
+import org.apache.servicecomb.authentication.util.Constants;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.core.userdetails.UserDetails;
@@ -29,23 +31,15 @@ import org.springframework.stereotype.Component;
 
 import com.netflix.config.DynamicPropertyFactory;
 
-@Component(value = "fefreshTokenTokenGranter")
+@Component
 public class RefreshTokenTokenGranter implements TokenGranter {
   @Autowired
-  @Qualifier("authUserDetailsService")
+  @Qualifier(Constants.BEAN_AUTH_USER_DETAILS_SERVICE)
   private UserDetailsService userDetailsService;
 
   @Autowired
-  @Qualifier("authAccessTokenStore")
-  private TokenStore accessTokenStore;
-
-  @Autowired
-  @Qualifier("authRefreshTokenStore")
-  private TokenStore refreshTokenStore;
-
-  @Autowired
-  @Qualifier("authIDTokenStore")
-  private TokenStore idTokenStore;
+  @Qualifier(Constants.BEAN_AUTH_OPEN_ID_TOKEN_STORE)
+  private AbstractOpenIDTokenStore openIDTokenStore;
 
   @Override
   public boolean enabled() {
@@ -63,22 +57,12 @@ public class RefreshTokenTokenGranter implements TokenGranter {
   public TokenResponse grant(Map<String, String> parameters) {
     String refreshTokenValue = parameters.get(TokenConst.PARAM_REFRESH_TOKEN);
 
-    Token refreshToken = refreshTokenStore.readTokenByValue(refreshTokenValue);
+    Token refreshToken = openIDTokenStore.readTokenByRefreshTokenValue(refreshTokenValue);
 
     if (refreshToken != null && !refreshToken.isExpired()) {
       UserDetails userDetails = userDetailsService.loadUserByUsername(refreshToken.username());
-
-      TokenResponse token = new TokenResponse();
-      token.setAccess_token(accessTokenStore.createToken(userDetails).getValue());
-      // refresh token is not generated 
-      token.setRefresh_token(refreshTokenValue);
-      token.setId_token(idTokenStore.createToken(userDetails).getValue());
-
-      //TODO add parameters.
-      token.setScope(null);
-      token.setExpires_in(10 * 60);
-      token.setToken_type("bearer");
-      return token;
+      OpenIDToken openIDToken = openIDTokenStore.createToken(userDetails);
+      return TokenResponse.fromOpenIDToken(openIDToken);
     }
     return null;
   }
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenResponse.java b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenResponse.java
index 9bdc6d7..32e7fb5 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenResponse.java
+++ b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenResponse.java
@@ -20,6 +20,8 @@ package org.apache.servicecomb.authentication.server;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.servicecomb.authentication.token.OpenIDToken;
+
 public class TokenResponse {
   // Naming conventions https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-00#section-3.1
   private String token_type;
@@ -31,13 +33,10 @@ public class TokenResponse {
   // Naming conventions https://openid.net/specs/openid-connect-basic-1_0.html#ObtainingTokens
   private String id_token;
 
-  private int expires_in;
+  private long expires_in;
 
   private Set<String> scope;
 
-  // JWT id
-  private String jti;
-
   private Map<String, Object> additionalInformation;
 
   public String getToken_type() {
@@ -64,11 +63,11 @@ public class TokenResponse {
     this.refresh_token = refresh_token;
   }
 
-  public int getExpires_in() {
+  public long getExpires_in() {
     return expires_in;
   }
 
-  public void setExpires_in(int expires_in) {
+  public void setExpires_in(long expires_in) {
     this.expires_in = expires_in;
   }
 
@@ -88,14 +87,6 @@ public class TokenResponse {
     this.scope = scope;
   }
 
-  public String getJti() {
-    return jti;
-  }
-
-  public void setJti(String jti) {
-    this.jti = jti;
-  }
-
   public Map<String, Object> getAdditionalInformation() {
     return additionalInformation;
   }
@@ -104,4 +95,17 @@ public class TokenResponse {
     this.additionalInformation = additionalInformation;
   }
 
+  public static TokenResponse fromOpenIDToken(OpenIDToken openIDToken) {
+    TokenResponse token = new TokenResponse();
+    token.setAccess_token(openIDToken.getAccessToken().getValue());
+    token.setRefresh_token(openIDToken.getRefreshToken().getValue());
+    token.setId_token(openIDToken.getIdToken().getValue());
+
+    token.setAdditionalInformation(openIDToken.getAdditionalInformation());
+    token.setScope(openIDToken.getScope());
+    token.setExpires_in(openIDToken.getExpiresIn());
+    token.setToken_type(openIDToken.getTokenType());
+
+    return token;
+  }
 }
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java b/api/common/endpoint/src/main/java/org/apache/servicecomb/authentication/token/TokenConfiguration.java
similarity index 55%
copy from samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
copy to api/common/endpoint/src/main/java/org/apache/servicecomb/authentication/token/TokenConfiguration.java
index e69217f..94b1e21 100644
--- a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
+++ b/api/common/endpoint/src/main/java/org/apache/servicecomb/authentication/token/TokenConfiguration.java
@@ -15,32 +15,30 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.authentication.resource;
+package org.apache.servicecomb.authentication.token;
 
-import org.apache.servicecomb.authentication.token.JWTTokenStore;
-import org.apache.servicecomb.authentication.token.TokenStore;
+import org.apache.servicecomb.authentication.util.Constants;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
+import org.springframework.core.annotation.Order;
 import org.springframework.security.jwt.crypto.sign.Signer;
 import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
-public class AuthenticationConfiguration {
-  @Bean(name = {"authSigner", "authSignatureVerifier"})
-  public SignerVerifier authSignerVerifier() {
-    // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
-    // If using MacSigner, need to protect the shared key by properly encryption.
-    return new MacSigner("Please change this key.");
+public class TokenConfiguration {
+  @Bean(name = {Constants.BEAN_AUTH_ACCESS_TOKEN_STORE,
+      Constants.BEAN_AUTH_REFRESH_TOKEN_STORE})
+  @Order(Constants.BEAN_DEFAULT_ORDER)
+  public SessionTokenStore sessionTokenStore() {
+    return new SessionTokenStore();
   }
 
-  @Bean(name = "authIDTokenStore")
-  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
-      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
-    return new JWTTokenStore(signer, signerVerifier);
+  @Bean(name = {Constants.BEAN_AUTH_ID_TOKEN_STORE})
+  @Order(Constants.BEAN_DEFAULT_ORDER)
+  public JWTTokenStore jwtTokenStore(@Autowired @Qualifier(Constants.BEAN_AUTH_SIGNER) Signer signer,
+      @Autowired @Qualifier(Constants.BEAN_AUTH_SIGNATURE_VERIFIER) SignerVerifier signerVerifier) {
+    return new JWTTokenStoreImpl(signer, signerVerifier);
   }
-
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractOpenIDTokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractOpenIDTokenStore.java
new file mode 100644
index 0000000..9bc43cf
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractOpenIDTokenStore.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.token;
+
+import org.apache.servicecomb.authentication.util.Constants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.core.userdetails.UserDetails;
+
+public abstract class AbstractOpenIDTokenStore implements OpenIDTokenStore {
+  @Autowired
+  @Qualifier(Constants.BEAN_AUTH_ACCESS_TOKEN_STORE)
+  private TokenStore<SessionToken> accessTokenStore;
+
+  @Autowired
+  @Qualifier(Constants.BEAN_AUTH_REFRESH_TOKEN_STORE)
+  private TokenStore<SessionToken> refreshTokenStore;
+
+  @Autowired
+  @Qualifier(Constants.BEAN_AUTH_ID_TOKEN_STORE)
+  private JWTTokenStore idTokenStore;
+
+  @Override
+  public JWTToken createIDTokenByValue(String jwtTokenValue) {
+    return idTokenStore.createTokenByValue(jwtTokenValue);
+  }
+
+  @Override
+  public OpenIDToken createToken(UserDetails userDetails) {
+    OpenIDToken token = new OpenIDToken();
+    token.setTokenType(Constants.TOKEN_TYPE_BEARER);
+    token.setAccessToken(accessTokenStore.createToken(userDetails));
+    token.setRefreshToken(refreshTokenStore.createToken(userDetails));
+    token.setIdToken(idTokenStore.createToken(userDetails));
+    return token;
+  }
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemoryOpenIDTokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemoryOpenIDTokenStore.java
new file mode 100644
index 0000000..522e475
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemoryOpenIDTokenStore.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.token;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class InMemoryOpenIDTokenStore extends AbstractOpenIDTokenStore {
+  private static final Map<String, OpenIDToken> TOKENS = new ConcurrentHashMap<>();
+
+  private static final Map<String, OpenIDToken> TOKENS_BY_REFRESH_TOKEN_VALUE = new ConcurrentHashMap<>();
+
+  private static final Map<String, OpenIDToken> TOKENS_BY_ID_TOKEN_VALUE = new ConcurrentHashMap<>();
+
+  @Override
+  public OpenIDToken readTokenByValue(String value) {
+    return TOKENS.get(value);
+  }
+
+  @Override
+  public OpenIDToken readTokenByRefreshTokenValue(String refreshTokenValue) {
+    return TOKENS_BY_REFRESH_TOKEN_VALUE.get(refreshTokenValue);
+  }
+
+  @Override
+  public OpenIDToken readTokenByIDTokenValue(String idTokenValue) {
+    return TOKENS_BY_ID_TOKEN_VALUE.get(idTokenValue);
+  }
+
+  @Override
+  public void saveToken(OpenIDToken token) {
+    TOKENS.put(token.getValue(), token);
+    TOKENS_BY_REFRESH_TOKEN_VALUE.put(token.getRefreshToken().getValue(), token);
+    TOKENS_BY_ID_TOKEN_VALUE.put(token.getIdToken().getValue(), token);
+  }
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemorySessionIDTokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemorySessionIDTokenStore.java
deleted file mode 100644
index 5bac8f0..0000000
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/InMemorySessionIDTokenStore.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.authentication.token;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.springframework.security.core.userdetails.UserDetails;
-
-public class InMemorySessionIDTokenStore extends AbstractSessionIDTokenStore {
-  private Map<String, SessionIDToken> tokens = new HashMap<>();
-
-  @SuppressWarnings("unchecked")
-  @Override
-  public <T extends Token> T createToken(UserDetails userDetails) {
-    SessionIDToken token = new SessionIDToken(userDetails.getUsername());
-    tokens.put(token.getValue(), token);
-    return (T) token;
-  }
-
-  @SuppressWarnings("unchecked")
-  @Override
-  public <T extends Token> T readTokenByValue(String value) {
-    return (T) tokens.get(value);
-  }
-
-}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java
index e989ae5..a4c6750 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java
@@ -17,69 +17,8 @@
 
 package org.apache.servicecomb.authentication.token;
 
-import java.util.Map;
-
 import org.apache.servicecomb.authentication.jwt.JWTClaims;
-import org.apache.servicecomb.authentication.jwt.JsonParser;
-import org.springframework.security.jwt.Jwt;
-import org.springframework.security.jwt.JwtHelper;
-import org.springframework.security.jwt.crypto.sign.Signer;
-
-public class JWTToken implements Token {
-  private JWTClaims claims;
-
-  private boolean valueCalculated = false;
-
-  private String value;
-
-  private Signer signer;
-
-  public JWTToken(JWTClaims claims, Signer signer) {
-    this.claims = claims;
-    this.signer = signer;
-  }
-
-  @Override
-  public boolean isExpired() {
-    return System.currentTimeMillis() - this.getIssueAt() > this.getExpiration() * 1000;
-  }
-
-  @Override
-  public long getIssueAt() {
-    return this.claims.getIat();
-  }
-
-  @Override
-  public long getExpiration() {
-    return this.claims.getExp();
-  }
-
-  @Override
-  public long getNotBefore() {
-    return this.claims.getNbf();
-  }
-
-  @Override
-  public String getValue() {
-    if (!this.valueCalculated) {
-      String content = JsonParser.unparse(claims);
-      Jwt jwtToken = JwtHelper.encode(content, signer);
-      this.value = jwtToken.getEncoded();
-    }
-    return this.value;
-  }
-
-  @Override
-  public Map<String, Object> getAdditionalInformation() {
-    return this.claims.getAdditionalInformation();
-  }
 
-  @Override
-  public String username() {
-    return this.claims.getSub();
-  }
-  
-  public JWTClaims getClaims() {
-    return this.claims;
-  }
+public interface JWTToken extends Token {
+  public JWTClaims getClaims();
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenImpl.java
similarity index 93%
copy from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java
copy to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenImpl.java
index e989ae5..0a99334 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTToken.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenImpl.java
@@ -25,7 +25,7 @@ import org.springframework.security.jwt.Jwt;
 import org.springframework.security.jwt.JwtHelper;
 import org.springframework.security.jwt.crypto.sign.Signer;
 
-public class JWTToken implements Token {
+public class JWTTokenImpl implements JWTToken {
   private JWTClaims claims;
 
   private boolean valueCalculated = false;
@@ -34,14 +34,14 @@ public class JWTToken implements Token {
 
   private Signer signer;
 
-  public JWTToken(JWTClaims claims, Signer signer) {
+  public JWTTokenImpl(JWTClaims claims, Signer signer) {
     this.claims = claims;
     this.signer = signer;
   }
 
   @Override
   public boolean isExpired() {
-    return System.currentTimeMillis() - this.getIssueAt() > this.getExpiration() * 1000;
+    return System.currentTimeMillis() - this.getIssueAt() > this.getExpiresIn() * 1000;
   }
 
   @Override
@@ -50,7 +50,7 @@ public class JWTToken implements Token {
   }
 
   @Override
-  public long getExpiration() {
+  public long getExpiresIn() {
     return this.claims.getExp();
   }
 
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java
index 2f394e7..67e51cc 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java
@@ -17,55 +17,6 @@
 
 package org.apache.servicecomb.authentication.token;
 
-import java.util.UUID;
-
-import org.apache.servicecomb.authentication.jwt.JWTClaims;
-import org.apache.servicecomb.authentication.jwt.JsonParser;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.jwt.Jwt;
-import org.springframework.security.jwt.JwtHelper;
-import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
-import org.springframework.security.jwt.crypto.sign.Signer;
-
-public class JWTTokenStore implements TokenStore {
-  private Signer signer;
-
-  private SignatureVerifier signerVerifier;
-
-  public JWTTokenStore(Signer signer, SignatureVerifier signerVerifier) {
-    this.signer = signer;
-    this.signerVerifier = signerVerifier;
-  }
-
-  @SuppressWarnings("unchecked")
-  @Override
-  public <T extends Token> T createToken(UserDetails userDetails) {
-    JWTClaims claims = new JWTClaims();
-    claims.setSub(userDetails.getUsername());
-    if (userDetails.getAuthorities() != null) {
-      userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority()));
-    }
-
-    // TODO : set other parameters.
-    claims.setJti(UUID.randomUUID().toString());
-    claims.setIat(System.currentTimeMillis());
-    claims.setExp(5 * 60);
-
-    return (T) new JWTToken(claims, signer);
-  }
-
-  @SuppressWarnings("unchecked")
-  @Override
-  public <T extends Token> T readTokenByValue(String value) {
-    Jwt jwt = JwtHelper.decode(value);
-    JWTClaims claims;
-    try {
-      jwt.verifySignature(signerVerifier);
-      claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
-    } catch (Exception e) {
-      return null;
-    }
-    return (T) new JWTToken(claims, signer);
-  }
-
+public interface JWTTokenStore extends TokenStore<JWTToken> {
+  public JWTToken createTokenByValue(String value);
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStoreImpl.java
similarity index 78%
copy from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java
copy to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStoreImpl.java
index 2f394e7..f7191c0 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStore.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenStoreImpl.java
@@ -27,19 +27,18 @@ import org.springframework.security.jwt.JwtHelper;
 import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
 import org.springframework.security.jwt.crypto.sign.Signer;
 
-public class JWTTokenStore implements TokenStore {
+public class JWTTokenStoreImpl implements JWTTokenStore {
   private Signer signer;
 
-  private SignatureVerifier signerVerifier;
+  private SignatureVerifier signatureVerifier;
 
-  public JWTTokenStore(Signer signer, SignatureVerifier signerVerifier) {
+  public JWTTokenStoreImpl(Signer signer, SignatureVerifier signatureVerifier) {
     this.signer = signer;
-    this.signerVerifier = signerVerifier;
+    this.signatureVerifier = signatureVerifier;
   }
 
-  @SuppressWarnings("unchecked")
   @Override
-  public <T extends Token> T createToken(UserDetails userDetails) {
+  public JWTToken createToken(UserDetails userDetails) {
     JWTClaims claims = new JWTClaims();
     claims.setSub(userDetails.getUsername());
     if (userDetails.getAuthorities() != null) {
@@ -51,21 +50,18 @@ public class JWTTokenStore implements TokenStore {
     claims.setIat(System.currentTimeMillis());
     claims.setExp(5 * 60);
 
-    return (T) new JWTToken(claims, signer);
+    return new JWTTokenImpl(claims, signer);
   }
 
-  @SuppressWarnings("unchecked")
-  @Override
-  public <T extends Token> T readTokenByValue(String value) {
+  public JWTToken createTokenByValue(String value) {
     Jwt jwt = JwtHelper.decode(value);
     JWTClaims claims;
     try {
-      jwt.verifySignature(signerVerifier);
+      jwt.verifySignature(signatureVerifier);
       claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
     } catch (Exception e) {
       return null;
     }
-    return (T) new JWTToken(claims, signer);
+    return new JWTTokenImpl(claims, signer);
   }
-
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDToken.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDToken.java
new file mode 100644
index 0000000..2587619
--- /dev/null
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDToken.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.authentication.token;
+
+import java.util.Map;
+import java.util.Set;
+
+public class OpenIDToken implements Token {
+  private String tokenType;
+
+  private SessionToken accessToken;
+
+  private SessionToken refreshToken;
+
+  private JWTToken idToken;
+
+  private Set<String> scope;
+
+  public String getTokenType() {
+    return tokenType;
+  }
+
+  public void setTokenType(String tokenType) {
+    this.tokenType = tokenType;
+  }
+
+  public SessionToken getAccessToken() {
+    return accessToken;
+  }
+
+  public void setAccessToken(SessionToken accessToken) {
+    this.accessToken = accessToken;
+  }
+
+  public SessionToken getRefreshToken() {
+    return refreshToken;
+  }
+
+  public void setRefreshToken(SessionToken refreshToken) {
+    this.refreshToken = refreshToken;
+  }
+
+  public JWTToken getIdToken() {
+    return idToken;
+  }
+
+  public void setIdToken(JWTToken idToken) {
+    this.idToken = idToken;
+  }
+
+  public Set<String> getScope() {
+    return scope;
+  }
+
+  public void setScope(Set<String> scope) {
+    this.scope = scope;
+  }
+
+  @Override
+  public String username() {
+    return accessToken.username();
+  }
+
+  @Override
+  public boolean isExpired() {
+    return accessToken.isExpired();
+  }
+
+  @Override
+  public long getIssueAt() {
+    return accessToken.getIssueAt();
+  }
+
+  @Override
+  public long getExpiresIn() {
+    return accessToken.getExpiresIn();
+  }
+
+  @Override
+  public long getNotBefore() {
+    return accessToken.getNotBefore();
+  }
+
+  @Override
+  public String getValue() {
+    return accessToken.getValue();
+  }
+
+  @Override
+  public Map<String, Object> getAdditionalInformation() {
+    return accessToken.getAdditionalInformation();
+  }
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDTokenStore.java
similarity index 71%
copy from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
copy to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDTokenStore.java
index 21b06d5..cd65ead 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDTokenStore.java
@@ -17,20 +17,15 @@
 
 package org.apache.servicecomb.authentication.token;
 
-import java.util.Map;
+public interface OpenIDTokenStore extends TokenStore<OpenIDToken> {
 
-public interface Token {
-  String username();
+  OpenIDToken readTokenByValue(String value);
 
-  boolean isExpired();
+  OpenIDToken readTokenByRefreshTokenValue(String refreshTokenValue);
 
-  long getIssueAt();
+  OpenIDToken readTokenByIDTokenValue(String idTokenValue);
+  
+  JWTToken createIDTokenByValue(String jwtTokenValue);
 
-  long getExpiration();
-
-  long getNotBefore();
-
-  String getValue();
-
-  Map<String, Object> getAdditionalInformation();
+  void saveToken(OpenIDToken token);
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractSessionIDTokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionToken.java
similarity index 92%
rename from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractSessionIDTokenStore.java
rename to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionToken.java
index cb507a3..c39cec4 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/AbstractSessionIDTokenStore.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionToken.java
@@ -17,5 +17,5 @@
 
 package org.apache.servicecomb.authentication.token;
 
-public abstract class AbstractSessionIDTokenStore implements TokenStore {
+public interface SessionToken extends Token {
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionIDToken.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenImpl.java
similarity index 87%
rename from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionIDToken.java
rename to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenImpl.java
index 06a6f96..53aa6d0 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionIDToken.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenImpl.java
@@ -20,27 +20,27 @@ package org.apache.servicecomb.authentication.token;
 import java.util.Map;
 import java.util.UUID;
 
-public class SessionIDToken implements Token {
+public class SessionTokenImpl implements SessionToken {
   private String value;
 
   private long issueAt;
 
   // in seconds
-  private long expiration;
+  private long expiresIn;
 
   private String username;
 
-  public SessionIDToken(String username) {
+  public SessionTokenImpl(String username) {
     this.value = UUID.randomUUID().toString();
     this.issueAt = System.currentTimeMillis();
     // TODO add a configuration
-    this.expiration = 600;
+    this.expiresIn = 600;
     this.username = username;
   }
 
   @Override
   public boolean isExpired() {
-    return System.currentTimeMillis() - this.issueAt > this.expiration * 1000;
+    return System.currentTimeMillis() - this.issueAt > this.expiresIn * 1000;
   }
 
   @Override
@@ -49,8 +49,8 @@ public class SessionIDToken implements Token {
   }
 
   @Override
-  public long getExpiration() {
-    return this.expiration;
+  public long getExpiresIn() {
+    return this.expiresIn;
   }
 
   @Override
@@ -70,6 +70,7 @@ public class SessionIDToken implements Token {
     return null;
   }
 
+  @Override
   public String username() {
     return this.username;
   }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenStore.java
similarity index 81%
copy from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java
copy to api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenStore.java
index 1f26610..59b23aa 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenStore.java
@@ -19,8 +19,11 @@ package org.apache.servicecomb.authentication.token;
 
 import org.springframework.security.core.userdetails.UserDetails;
 
-public interface TokenStore {
-  <T extends Token> T createToken(UserDetails userDetails);
-  
-  <T extends Token> T readTokenByValue(String value);
+public class SessionTokenStore implements TokenStore<SessionToken> {
+
+  @Override
+  public SessionToken createToken(UserDetails userDetails) {
+    return new SessionTokenImpl(userDetails.getUsername());
+  }
+
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
index 21b06d5..29b26db 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
@@ -26,7 +26,7 @@ public interface Token {
 
   long getIssueAt();
 
-  long getExpiration();
+  long getExpiresIn();
 
   long getNotBefore();
 
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java
index 1f26610..e4b6df1 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/TokenStore.java
@@ -19,8 +19,6 @@ package org.apache.servicecomb.authentication.token;
 
 import org.springframework.security.core.userdetails.UserDetails;
 
-public interface TokenStore {
-  <T extends Token> T createToken(UserDetails userDetails);
-  
-  <T extends Token> T readTokenByValue(String value);
+public interface TokenStore<T extends Token> {
+  T createToken(UserDetails userDetails);
 }
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java
index 4dcc8e7..43c85b5 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/util/Constants.java
@@ -22,8 +22,35 @@ public final class Constants {
 
   public static final String CONTEXT_HEADER_AUTHORIZATION = "Authorization";
 
+  public static final String CONTEXT_HEADER_AUTHORIZATION_TYPE = "Authorization-TYPE";
+  
+  public static final String CONTEXT_HEADER_AUTHORIZATION_TYPE_ID_TOKEN = "ID_TOKEN";
+  
+  public static final String CONTEXT_HEADER_AUTHORIZATION_TYPE_SESSION_TOKEN = "SESSION_TOKEN";
+  
   public static final String CONTEXT_HEADER_CLAIMS = "Claims";
 
   public static final String TOKEN_TYPE_BEARER = "Bearer";
 
+  public static final int BEAN_DEFAULT_ORDER = 100;
+
+  public static final String BEAN_AUTH_EDGE_TOKEN_RESPONSE_PROCESSOR = "edgeTokenResponseProcessor";
+
+  public static final String BEAN_AUTH_SIGNER = "authSigner";
+
+  public static final String BEAN_AUTH_SIGNATURE_VERIFIER = "authSignatureVerifier";
+
+  public static final String BEAN_AUTH_PASSWORD_ENCODER = "authPasswordEncoder";
+
+  public static final String BEAN_AUTH_ACCESS_TOKEN_STORE = "authAccessTokenStore";
+
+  public static final String BEAN_AUTH_REFRESH_TOKEN_STORE = "authRefreshTokenStore";
+
+  public static final String BEAN_AUTH_ID_TOKEN_STORE = "authIDTokenStore";
+
+  public static final String BEAN_AUTH_OPEN_ID_TOKEN_STORE = "authOpenIDTokenStore";
+  
+  public static final String BEAN_AUTH_USER_DETAILS_SERVICE = "authUserDetailsService";
+  
+  public static final String CONFIG_GRANTER_PASSWORD_ENABLED = "servicecomb.authentication.granter.password.enabled";
 }
diff --git a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
index d209be4..850b733 100644
--- a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
@@ -17,7 +17,10 @@
 
 package org.apache.servicecomb.authentication.edge;
 
-import org.apache.servicecomb.authentication.server.TokenResponse;
+import org.apache.servicecomb.authentication.token.JWTToken;
+import org.apache.servicecomb.authentication.token.JWTTokenStore;
+import org.apache.servicecomb.authentication.token.OpenIDToken;
+import org.apache.servicecomb.authentication.token.OpenIDTokenStore;
 import org.apache.servicecomb.authentication.util.Constants;
 import org.apache.servicecomb.core.Handler;
 import org.apache.servicecomb.core.Invocation;
@@ -25,27 +28,43 @@ import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.swagger.invocation.AsyncResponse;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 
-
 public class AuthHandler implements Handler {
   @Override
   public void handle(Invocation invocation, AsyncResponse asyncResponse) throws Exception {
-    EdgeTokenStore edgeTokenStore = BeanUtils.getBean("authEdgeTokenStore");
-
     String token = invocation.getContext(Constants.CONTEXT_HEADER_AUTHORIZATION);
+    String tokenType = invocation.getContext(Constants.CONTEXT_HEADER_AUTHORIZATION_TYPE);
     if (token == null) {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
     }
 
-    TokenResponse tokenResonse = edgeTokenStore.readTokenResponse(token);
-    if (tokenResonse == null) {
-      // TODO : check token validity by expiration time
+    if (Constants.CONTEXT_HEADER_AUTHORIZATION_TYPE_ID_TOKEN.equals(tokenType)) {
+      JWTTokenStore jwtTokenStore = BeanUtils.getBean(Constants.BEAN_AUTH_ID_TOKEN_STORE);
+      JWTToken jwtToken = jwtTokenStore.createTokenByValue(token);
+      if (jwtToken == null || jwtToken.isExpired()) {
+        asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
+        return;
+      }
+
+      // send id_token to services to apply state less validation
+      invocation.addContext(Constants.CONTEXT_HEADER_AUTHORIZATION, jwtToken.getValue());
+      invocation.next(asyncResponse);
+    } else if (Constants.CONTEXT_HEADER_AUTHORIZATION_TYPE_SESSION_TOKEN.equals(tokenType)) {
+      OpenIDTokenStore openIDTokenStore = BeanUtils.getBean(Constants.BEAN_AUTH_OPEN_ID_TOKEN_STORE);
+
+
+      OpenIDToken tokenResonse = openIDTokenStore.readTokenByValue(token);
+      if (tokenResonse == null || tokenResonse.isExpired()) {
+        asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
+        return;
+      }
+
+      // send id_token to services to apply state less validation
+      invocation.addContext(Constants.CONTEXT_HEADER_AUTHORIZATION, tokenResonse.getIdToken().getValue());
+      invocation.next(asyncResponse);
+    } else {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
     }
-
-    // send id_token to services to apply state less validation
-    invocation.addContext(Constants.CONTEXT_HEADER_AUTHORIZATION, tokenResonse.getId_token());
-    invocation.next(asyncResponse);
   }
 }
diff --git a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java
index 46ba288..6b5b8d7 100644
--- a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationFilter.java
@@ -32,12 +32,16 @@ public class AuthenticationFilter implements HttpServerFilter {
 
   @Override
   public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) {
+    // Now support bearer id tokens authentication
+    // TODO : add support for Cookies session tokens. 
     String authentication = requestEx.getHeader(Constants.HTTP_HEADER_AUTHORIZATION);
     if (authentication != null) {
       String[] tokens = authentication.split(" ");
       if (tokens.length == 2) {
-        if (tokens[0].equals("Bearer")) {
+        if (tokens[0].equals(Constants.TOKEN_TYPE_BEARER)) {
           invocation.addContext(Constants.CONTEXT_HEADER_AUTHORIZATION, tokens[1]);
+          invocation.addContext(Constants.CONTEXT_HEADER_AUTHORIZATION_TYPE,
+              Constants.CONTEXT_HEADER_AUTHORIZATION_TYPE_ID_TOKEN);
         }
       }
     }
diff --git a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/DumyEdgeTokenResponseProcessor.java
similarity index 82%
copy from api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java
copy to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/DumyEdgeTokenResponseProcessor.java
index 92bbbaf..97dd3c4 100644
--- a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/DumyEdgeTokenResponseProcessor.java
@@ -19,8 +19,12 @@ package org.apache.servicecomb.authentication.edge;
 
 import org.apache.servicecomb.authentication.server.TokenResponse;
 
-public interface EdgeTokenStore {
-  TokenResponse readTokenResponse(String accessTokenValue);
+public class DumyEdgeTokenResponseProcessor implements EdgeTokenResponseProcessor {
+  public DumyEdgeTokenResponseProcessor() {
+  }
+
+  @Override
+  public void process(TokenResponse tokenResponse) {
+  }
 
-  void saveTokenResponse(String accessTokenValue, TokenResponse tokenResponse);
 }
diff --git a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/InMemoryEdgeTokenStore.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeConfiguration.java
similarity index 62%
rename from api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/InMemoryEdgeTokenStore.java
rename to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeConfiguration.java
index 03a7baa..502dc7e 100644
--- a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/InMemoryEdgeTokenStore.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeConfiguration.java
@@ -17,22 +17,16 @@
 
 package org.apache.servicecomb.authentication.edge;
 
-import java.util.HashMap;
-import java.util.Map;
+import org.apache.servicecomb.authentication.util.Constants;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
 
-import org.apache.servicecomb.authentication.server.TokenResponse;
-
-public class InMemoryEdgeTokenStore implements EdgeTokenStore {
-  private Map<String, TokenResponse> tokens = new HashMap<>();
-
-  @Override
-  public TokenResponse readTokenResponse(String accessTokenValue) {
-    return tokens.get(accessTokenValue);
+@Configuration
+public class EdgeConfiguration {
+  @Bean(name = {Constants.BEAN_AUTH_EDGE_TOKEN_RESPONSE_PROCESSOR})
+  @Order(Constants.BEAN_DEFAULT_ORDER)
+  public EdgeTokenResponseProcessor edgeTokenResponseProcessor() {
+    return new DumyEdgeTokenResponseProcessor();
   }
-
-  @Override
-  public void saveTokenResponse(String accessTokenValue, TokenResponse tokenResponse) {
-    tokens.put(accessTokenValue, tokenResponse);
-  }
-
 }
diff --git a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenResponseProcessor.java
similarity index 84%
rename from api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java
rename to api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenResponseProcessor.java
index 92bbbaf..09ea7b3 100644
--- a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenStore.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/EdgeTokenResponseProcessor.java
@@ -19,8 +19,6 @@ package org.apache.servicecomb.authentication.edge;
 
 import org.apache.servicecomb.authentication.server.TokenResponse;
 
-public interface EdgeTokenStore {
-  TokenResponse readTokenResponse(String accessTokenValue);
-
-  void saveTokenResponse(String accessTokenValue, TokenResponse tokenResponse);
+public interface EdgeTokenResponseProcessor {
+  void process(TokenResponse tokenResponse);
 }
diff --git a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/TokenEndpoint.java b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/TokenEndpoint.java
index 87dcbb0..87f7696 100644
--- a/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/TokenEndpoint.java
+++ b/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/TokenEndpoint.java
@@ -21,6 +21,7 @@ import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 
 import org.apache.servicecomb.authentication.server.TokenResponse;
+import org.apache.servicecomb.authentication.util.Constants;
 import org.apache.servicecomb.provider.pojo.RpcReference;
 import org.apache.servicecomb.provider.rest.common.RestSchema;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -38,9 +39,8 @@ public class TokenEndpoint implements TokenService {
   private AuthenticationServerTokenEndpoint authenticationSererTokenEndpoint;
 
   @Autowired
-  @Qualifier("authEdgeTokenStore")
-  private EdgeTokenStore edgeTokenStore;
-
+  @Qualifier(Constants.BEAN_AUTH_EDGE_TOKEN_RESPONSE_PROCESSOR)
+  private EdgeTokenResponseProcessor edgeTokenResponseProcessor;
 
   @Override
   @PostMapping(path = "/", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@@ -55,7 +55,7 @@ public class TokenEndpoint implements TokenService {
     response.whenComplete((tokenResonse, ex) -> {
       if (!response.isCompletedExceptionally()) {
         result.complete(tokenResonse);
-        edgeTokenStore.saveTokenResponse(tokenResonse.getAccess_token(), tokenResonse);
+        edgeTokenResponseProcessor.process(tokenResonse);
       } else {
         result.completeExceptionally(ex);
       }
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
index 5c81139..73f0b1a 100644
--- a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
@@ -48,25 +48,25 @@ public class ResourceAuthHandler implements Handler {
       return;
     }
 
-    String token = invocation.getContext(Constants.CONTEXT_HEADER_AUTHORIZATION);
-    if (token == null) {
+    String idTokenValue = invocation.getContext(Constants.CONTEXT_HEADER_AUTHORIZATION);
+    if (idTokenValue == null) {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
     }
     // verify tokens
-    JWTTokenStore store = BeanUtils.getBean("authIDTokenStore");
-    JWTToken t = store.readTokenByValue(token);
-    if(t == null) {
+    JWTTokenStore store = BeanUtils.getBean(Constants.BEAN_AUTH_ID_TOKEN_STORE);
+    JWTToken idToken = store.createTokenByValue(idTokenValue);
+    if (idToken == null) {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
     }
-    
+
     // check roles
     if (!StringUtils.isEmpty(config.roles)) {
       String[] roles = config.roles.split(",");
       if (roles.length > 0) {
         boolean valid = false;
-        Set<String> authorities = t.getClaims().getAuthorities();
+        Set<String> authorities = idToken.getClaims().getAuthorities();
         for (String role : roles) {
           if (authorities.contains(role)) {
             valid = true;
@@ -81,8 +81,8 @@ public class ResourceAuthHandler implements Handler {
     }
 
     // pre method authentiation
-    Set<GrantedAuthority> grantedAuthorities = new HashSet<>(t.getClaims().getAuthorities().size());
-    t.getClaims().getAuthorities().forEach(v -> grantedAuthorities.add(new SimpleGrantedAuthority(v)));
+    Set<GrantedAuthority> grantedAuthorities = new HashSet<>(idToken.getClaims().getAuthorities().size());
+    idToken.getClaims().getAuthorities().forEach(v -> grantedAuthorities.add(new SimpleGrantedAuthority(v)));
     SecurityContext sc = new SecurityContextImpl();
     Authentication authentication = new SimpleAuthentication(true, grantedAuthorities);
     sc.setAuthentication(authentication);
diff --git a/docs/zh_CN/developersGuide.md b/docs/zh_CN/developersGuide.md
index 3d67833..a681c5a 100644
--- a/docs/zh_CN/developersGuide.md
+++ b/docs/zh_CN/developersGuide.md
@@ -22,16 +22,7 @@ grant_type=password&username=admin&password=changeMyPassword
     "token_type": "bearer",
     "access_token": "SlAV32hkKG",
     "refresh_token": "8xLOxBtZp8",
-    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
-     yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
-     NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
-     fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
-     AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
-     Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
-     NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
-     QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
-     K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
-     XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg",
+    "id_token": "eyJ...hbGciOiJSU...zI1NiIsImtpZCI6Ij",
     "expires_in": 600,
     "scope": null,
     "jti": null,
@@ -48,7 +39,7 @@ grant_type=password&username=admin&password=changeMyPassword
 
 POST http://localhost:9090/api/resource-server/v1/auth/handler/adminSayHello?name=Hi HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
-Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW
+Authorization: Bearer SlAV32hkKG
 ```
 
   * Edge Service 将 Access Token 转换为对应的 ID Token , 然后将请求转发给Resource Server。
diff --git a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
index 20e9f68..49639ff 100644
--- a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
+++ b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
@@ -19,9 +19,9 @@ package org.apache.servicecomb.authentication;
 
 import java.util.Arrays;
 
-import org.apache.servicecomb.authentication.token.InMemorySessionIDTokenStore;
-import org.apache.servicecomb.authentication.token.JWTTokenStore;
-import org.apache.servicecomb.authentication.token.TokenStore;
+import org.apache.servicecomb.authentication.token.AbstractOpenIDTokenStore;
+import org.apache.servicecomb.authentication.token.InMemoryOpenIDTokenStore;
+import org.apache.servicecomb.authentication.util.Constants;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Bean;
@@ -33,41 +33,33 @@ import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
-import org.springframework.security.jwt.crypto.sign.Signer;
 import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authPasswordEncoder")
+  @Bean(name = Constants.BEAN_AUTH_PASSWORD_ENCODER)
   public PasswordEncoder authPasswordEncoder() {
     return new Pbkdf2PasswordEncoder();
   }
 
-  @Bean(name = {"authSigner", "authSignatureVerifier"})
+  @Bean(name = {Constants.BEAN_AUTH_SIGNER, Constants.BEAN_AUTH_SIGNATURE_VERIFIER})
   public SignerVerifier authSignerVerifier() {
     // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
     // If using MacSigner, need to protect the shared key by properly encryption.
     return new MacSigner("Please change this key.");
   }
 
-  @Bean(name = {"authAccessTokenStore", "authRefreshTokenStore"})
-  public TokenStore sessionIDTokenStore() {
-    // Use in memory store for testing. Need to implement JDBC or Redis SessionIDTokenStore in product. 
-    return new InMemorySessionIDTokenStore();
+  @Bean(name = Constants.BEAN_AUTH_OPEN_ID_TOKEN_STORE)
+  public AbstractOpenIDTokenStore openIDTokenStore() {
+    // TODO: Use in memory store for testing. Need to implement JDBC or Redis SessionIDTokenStore in product. 
+    return new InMemoryOpenIDTokenStore();
   }
 
-  @Bean(name = "authIDTokenStore")
-  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
-      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
-    return new JWTTokenStore(signer, signerVerifier);
-  }
-
-  @Bean(name = "authUserDetailsService")
+  @Bean(name = Constants.BEAN_AUTH_USER_DETAILS_SERVICE)
   public UserDetailsService authUserDetailsService(
-      @Autowired @Qualifier("authPasswordEncoder") PasswordEncoder passwordEncoder) {
-    // Use in memory UserDetails, need to implement JDBC or others in product
+      @Autowired @Qualifier(Constants.BEAN_AUTH_PASSWORD_ENCODER) PasswordEncoder passwordEncoder) {
+    // TODO: Use in memory UserDetails, need to implement JDBC or others in product
     InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
     UserDetails uAdmin = new User("admin", passwordEncoder.encode("changeMyPassword"),
         Arrays.asList(new SimpleGrantedAuthority("ADMIN")));
diff --git a/samples/Client/pom.xml b/samples/Client/pom.xml
index d879756..5bbe9d8 100644
--- a/samples/Client/pom.xml
+++ b/samples/Client/pom.xml
@@ -33,11 +33,6 @@
     <dependencies>
       <dependency>
         <groupId>org.apache.servicecomb.authentication</groupId>
-        <artifactId>authentication-common-api-endpoint</artifactId>
-        <version>0.0.1-SNAPSHOT</version>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.servicecomb.authentication</groupId>
         <artifactId>authentication-server-api-service</artifactId>
         <version>0.0.1-SNAPSHOT</version>
       </dependency>
@@ -69,10 +64,6 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.servicecomb.authentication</groupId>
-      <artifactId>authentication-common-api-endpoint</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.servicecomb.authentication</groupId>
       <artifactId>authentication-server-api-service</artifactId>
     </dependency>
     <dependency>
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
index e05545f..eb13bf1 100644
--- a/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java
@@ -18,6 +18,7 @@
 package org.apache.servicecomb.authentication;
 
 import org.apache.servicecomb.authentication.server.TokenResponse;
+import org.apache.servicecomb.authentication.util.Constants;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
@@ -30,16 +31,16 @@ import org.springframework.web.client.HttpClientErrorException;
 public class AuthenticationTestCase implements TestCase {
   @Override
   public void run() {
-    String accessToken = accessToken();
-    testHanlderAuth(accessToken);
-    testMethodAuth(accessToken);
+    String idToken = idToken();
+    testHanlderAuth(idToken);
+    testMethodAuth(idToken);
 
-    accessToken = accessTokenByRefreshToken();
-    testHanlderAuth(accessToken);
-    testMethodAuth(accessToken);
+    idToken = idTokenByRefreshToken();
+    testHanlderAuth(idToken);
+    testMethodAuth(idToken);
   }
 
-  private String accessToken() {
+  private String idToken() {
     // get token
     MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
     map.add("grant_type", "password");
@@ -52,12 +53,12 @@ public class AuthenticationTestCase implements TestCase {
         BootEventListener.edgeServiceTokenEndpoint.postForObject("/",
             new HttpEntity<>(map, headers),
             TokenResponse.class);
-    TestMgr.check("bearer", token.getToken_type());
-    TestMgr.check(true, token.getAccess_token().length() > 10);
-    return token.getAccess_token();
+    TestMgr.check(Constants.TOKEN_TYPE_BEARER, token.getToken_type());
+    TestMgr.check(true, token.getId_token().length() > 10);
+    return token.getId_token();
   }
 
-  private String accessTokenByRefreshToken() {
+  private String idTokenByRefreshToken() {
     // get token
     MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
     map.add("grant_type", "password");
@@ -70,7 +71,7 @@ public class AuthenticationTestCase implements TestCase {
         BootEventListener.edgeServiceTokenEndpoint.postForObject("/",
             new HttpEntity<>(map, headers),
             TokenResponse.class);
-    TestMgr.check("bearer", token.getToken_type());
+    TestMgr.check(Constants.TOKEN_TYPE_BEARER, token.getToken_type());
     TestMgr.check(true, token.getAccess_token().length() > 10);
 
     // refresh token
@@ -83,11 +84,11 @@ public class AuthenticationTestCase implements TestCase {
             new HttpEntity<>(map, headers),
             TokenResponse.class);
     TestMgr.check(token.getToken_type(), tokenNew.getToken_type());
-    TestMgr.check(token.getRefresh_token(), tokenNew.getRefresh_token());
+    TestMgr.check(token.getRefresh_token().equals(tokenNew.getRefresh_token()), false);
     TestMgr.check(token.getAccess_token().equals(tokenNew.getAccess_token()), false);
     TestMgr.check(token.getId_token().equals(tokenNew.getId_token()), false);
 
-    return tokenNew.getAccess_token();
+    return tokenNew.getId_token();
   }
 
   private void testHanlderAuth(String accessToken) {
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java
index 19b0af1..a89f8c2 100644
--- a/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java
@@ -32,19 +32,25 @@ public class TestEndpoint {
 
   @GetMapping(path = "/start")
   public String start() {
-    tests.forEach(test -> test.run());
+    tests.forEach(test -> {
+      try {
+        test.run();
+      } catch (Throwable e) {
+        TestMgr.failed(e.getMessage(), e);
+      }
+    });
+
+    TestMgr.summary();
 
     List<Throwable> errors = TestMgr.errors();
     if (TestMgr.isSuccess()) {
       return TestMgr.successMessage();
     } else {
-      TestMgr.summary();
-
       StringBuilder sb = new StringBuilder();
       sb.append("Failed count : " + errors.size());
       sb.append("\n");
       errors.forEach(t -> sb.append(t.getMessage() + "\n"));
-      
+
       TestMgr.reset();
       return sb.toString();
     }
diff --git a/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java
index 030bb4c..c9e71fe 100644
--- a/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java
+++ b/samples/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java
@@ -71,9 +71,9 @@ public class TestMgr {
   }
 
   public static void failed(String desc, Throwable e) {
-    Error error = new Error(msg + " | " + desc + ", method is " + getCaller());
+    Error error = new Error(msg + " | " + desc + ", method is " + getCaller() + " , error type is " + e.getClass().toString());
     if (e != null) {
-      error.setStackTrace(error.getStackTrace());
+      error.setStackTrace(e.getStackTrace());
     }
     errorList.add(error);
   }
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
index e9187b7..62ab060 100644
--- a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
@@ -17,15 +17,30 @@
 
 package org.apache.servicecomb.authentication.gateway;
 
-import org.apache.servicecomb.authentication.edge.EdgeTokenStore;
-import org.apache.servicecomb.authentication.edge.InMemoryEdgeTokenStore;
+import org.apache.servicecomb.authentication.token.JWTTokenStore;
+import org.apache.servicecomb.authentication.token.JWTTokenStoreImpl;
+import org.apache.servicecomb.authentication.util.Constants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.security.jwt.crypto.sign.MacSigner;
+import org.springframework.security.jwt.crypto.sign.Signer;
+import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authEdgeTokenStore")
-  public EdgeTokenStore authEdgeTokenStore() {
-    return new InMemoryEdgeTokenStore();
+  @Bean(name = {Constants.BEAN_AUTH_SIGNER, Constants.BEAN_AUTH_SIGNATURE_VERIFIER})
+  public SignerVerifier authSignerVerifier() {
+    // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
+    // If using MacSigner, need to protect the shared key by properly encryption.
+    return new MacSigner("Please change this key.");
   }
+
+  @Bean(name = Constants.BEAN_AUTH_ID_TOKEN_STORE)
+  public JWTTokenStore authIDTokenStore(@Autowired @Qualifier(Constants.BEAN_AUTH_SIGNER) Signer signer, 
+      @Autowired @Qualifier(Constants.BEAN_AUTH_SIGNATURE_VERIFIER) SignerVerifier signerVerifier) {
+    return new JWTTokenStoreImpl(signer, signerVerifier);
+  }
+
 }
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
index e69217f..b1dcb00 100644
--- a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
@@ -18,29 +18,29 @@
 package org.apache.servicecomb.authentication.resource;
 
 import org.apache.servicecomb.authentication.token.JWTTokenStore;
-import org.apache.servicecomb.authentication.token.TokenStore;
+import org.apache.servicecomb.authentication.token.JWTTokenStoreImpl;
+import org.apache.servicecomb.authentication.util.Constants;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
 import org.springframework.security.jwt.crypto.sign.Signer;
 import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = {"authSigner", "authSignatureVerifier"})
+  @Bean(name = {Constants.BEAN_AUTH_SIGNER, Constants.BEAN_AUTH_SIGNATURE_VERIFIER})
   public SignerVerifier authSignerVerifier() {
     // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
     // If using MacSigner, need to protect the shared key by properly encryption.
     return new MacSigner("Please change this key.");
   }
 
-  @Bean(name = "authIDTokenStore")
-  public TokenStore authIDTokenStore(@Autowired @Qualifier("authSigner") Signer signer,
-      @Autowired @Qualifier("authSignatureVerifier") SignatureVerifier signerVerifier) {
-    return new JWTTokenStore(signer, signerVerifier);
+  @Bean(name = Constants.BEAN_AUTH_ID_TOKEN_STORE)
+  public JWTTokenStore authIDTokenStore(@Autowired @Qualifier(Constants.BEAN_AUTH_SIGNER) Signer signer, 
+      @Autowired @Qualifier(Constants.BEAN_AUTH_SIGNATURE_VERIFIER) SignerVerifier signerVerifier) {
+    return new JWTTokenStoreImpl(signer, signerVerifier);
   }
 
 }


[servicecomb-fence] 05/09: Merge pull request #2 from liubao68/master

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit 199f7a341878ccad826237533b8cb30c28d6fdb0
Merge: b4451da 1d2e250
Author: bao liu <ba...@huawei.com>
AuthorDate: Fri May 31 17:03:02 2019 +0800

    Merge pull request #2 from liubao68/master
    
    [SCB-1293]add TokenStore to support stateless and stateful session management

 .../server/PasswordTokenGranter.java               |  51 ++++-----
 .../server/RefreshTokenTokenGranter.java           |  77 ++++++--------
 .../authentication/server/TokenEndpoint.java       |   6 +-
 .../authentication/server/TokenGranter.java        |   4 +-
 api/authentication-server/service/pom.xml          |   8 ++
 .../server/{Token.java => TokenResponse.java}      |  13 ++-
 .../authentication/server/TokenService.java        |   2 +-
 .../token/AbstractSessionIDTokenStore.java}        |   7 +-
 .../token/InMemorySessionIDTokenStore.java}        |  32 +++---
 .../servicecomb/authentication/token/JWTToken.java |  85 +++++++++++++++
 .../authentication/token/JWTTokenStore.java        |  71 +++++++++++++
 .../authentication/token/SessionIDToken.java       |  76 +++++++++++++
 .../servicecomb/authentication/token/Token.java}   |  18 +++-
 .../authentication/token/TokenStore.java}          |  10 +-
 .../servicecomb/authentication/util/Constants.java |   5 +-
 .../authentication/edge/AuthHandler.java           |  17 +--
 .../authentication/edge/AuthenticationFilter.java  |   0
 .../edge/AuthenticationServerTokenEndpoint.java}   |  27 ++---
 .../edge/CustomVertxRestDispatcher.java            |   1 +
 .../authentication/edge/EdgeTokenStore.java}       |  10 +-
 .../edge/InMemoryEdgeTokenStore.java}              |  28 +++--
 .../authentication/edge/InternalAccessHandler.java |   0
 .../authentication/edge/TokenEndpoint.java         |  65 ++++++++++++
 ...servicecomb.common.rest.filter.HttpServerFilter |   0
 ...cecomb.transport.rest.vertx.VertxHttpDispatcher |   2 +-
 .../src/main/resources/config/cse.handler.xml      |   0
 api/edge-service/service/pom.xml                   |   3 +-
 .../authentication/edge}/TokenService.java         |   8 +-
 .../resource/ResourceAuthHandler.java              |  24 ++---
 docs/zh_CN/developersGuide.md                      |  97 ++++++++++++-----
 .../AuthenticationConfiguration.java               |  30 ++++--
 .../authentication/AuthenticationTestCase.java     | 117 ++++++++-------------
 .../authentication/BootEventListener.java          |   7 +-
 .../authentication/GateRestTemplate.java           |   9 ++
 .../gateway/AuthenticationConfiguration.java       |  10 +-
 .../resource/AuthenticationConfiguration.java      |  19 +++-
 36 files changed, 652 insertions(+), 287 deletions(-)