diff --git a/oauth2-framework-impl/oauth2-authorization-server/pom.xml b/oauth2-framework-impl/oauth2-authorization-server/pom.xml
new file mode 100644
index 0000000000..8db2150558
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/pom.xml
@@ -0,0 +1,72 @@
+
+
+ 4.0.0
+
+ oauth2-authorization-server
+ war
+
+
+ com.baeldung.oauth2
+ oauth2-framework-impl
+ 1.0-SNAPSHOT
+
+
+
+ 1.4.199
+ 9080
+ 9443
+
+
+
+
+ com.nimbusds
+ nimbus-jose-jwt
+ 7.3
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.62
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ 1.62
+
+
+
+
+
+ net.wasdev.wlp.maven.plugins
+ liberty-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-h2-dependency
+ package
+
+ copy
+
+
+
+
+
+
+ com.h2database
+ h2
+ ${h2.version}
+ jar
+ ${project.build.directory}/liberty/wlp/usr/shared/resources/
+
+
+
+
+
+
+
+
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/OAuth2ServerApplication.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/OAuth2ServerApplication.java
new file mode 100644
index 0000000000..62d6b04464
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/OAuth2ServerApplication.java
@@ -0,0 +1,8 @@
+package com.baeldung.oauth2.authorization.server;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+@ApplicationPath("/")
+public class OAuth2ServerApplication extends Application {
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/PEMKeyUtils.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/PEMKeyUtils.java
new file mode 100644
index 0000000000..dab57b91a7
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/PEMKeyUtils.java
@@ -0,0 +1,17 @@
+package com.baeldung.oauth2.authorization.server;
+
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import static java.lang.Thread.currentThread;
+
+
+public class PEMKeyUtils {
+
+ public static String readKeyAsString(String keyLocation) throws Exception {
+ URI uri = currentThread().getContextClassLoader().getResource(keyLocation).toURI();
+ byte[] byteArray = Files.readAllBytes(Paths.get(uri));
+ return new String(byteArray);
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/AuthorizationEndpoint.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/AuthorizationEndpoint.java
new file mode 100644
index 0000000000..10e78a2dfd
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/AuthorizationEndpoint.java
@@ -0,0 +1,185 @@
+package com.baeldung.oauth2.authorization.server.api;
+
+import com.baeldung.oauth2.authorization.server.handler.AuthorizationGrantTypeHandler;
+import com.baeldung.oauth2.authorization.server.model.AppDataRepository;
+import com.baeldung.oauth2.authorization.server.model.AuthorizationCode;
+import com.baeldung.oauth2.authorization.server.model.Client;
+import com.baeldung.oauth2.authorization.server.model.User;
+
+import javax.annotation.security.RolesAllowed;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.literal.NamedLiteral;
+import javax.inject.Inject;
+import javax.json.JsonObject;
+import javax.security.enterprise.SecurityContext;
+import javax.security.enterprise.authentication.mechanism.http.FormAuthenticationMechanismDefinition;
+import javax.security.enterprise.authentication.mechanism.http.LoginToContinue;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
+import java.io.IOException;
+import java.net.URI;
+import java.security.Principal;
+import java.time.LocalDateTime;
+import java.util.*;
+
+@FormAuthenticationMechanismDefinition(
+ loginToContinue = @LoginToContinue(loginPage = "/login.jsp", errorPage = "/login.jsp")
+)
+@RolesAllowed("USER")
+@RequestScoped
+@Path("authorize")
+public class AuthorizationEndpoint {
+
+ @Inject
+ private SecurityContext securityContext;
+
+ @Inject
+ private AppDataRepository appDataRepository;
+
+ @Inject
+ Instance authorizationGrantTypeHandlers;
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response doGet(@Context HttpServletRequest request,
+ @Context HttpServletResponse response,
+ @Context UriInfo uriInfo) throws ServletException, IOException {
+ MultivaluedMap params = uriInfo.getQueryParameters();
+ Principal principal = securityContext.getCallerPrincipal();
+
+ //error about redirect_uri && client_id ==> forward user, thus to error.jsp.
+ //otherwise ==> sendRedirect redirect_uri?error=error&error_description=error_description
+ //1. client_id
+ String clientId = params.getFirst("client_id");
+ if (clientId == null || clientId.isEmpty()) {
+ return informUserAboutError(request, response, "Invalid client_id :" + clientId);
+ }
+ Client client = appDataRepository.getClient(clientId);
+ if (client == null) {
+ return informUserAboutError(request, response, "Invalid client_id :" + clientId);
+ }
+ //2. Client Authorized Grant Type
+ String clientError = "";
+ if (client.getAuthorizedGrantTypes() != null && !client.getAuthorizedGrantTypes().contains("authorization_code")) {
+ return informUserAboutError(request, response, "Authorization Grant type, authorization_code, is not allowed for this client :" + clientId);
+ }
+
+ //3. redirectUri
+ String redirectUri = params.getFirst("redirect_uri");
+ if (client.getRedirectUri() != null && !client.getRedirectUri().isEmpty()) {
+ if (redirectUri != null && !redirectUri.isEmpty() && !client.getRedirectUri().equals(redirectUri)) {
+ //sould be in the client.redirectUri
+ return informUserAboutError(request, response, "redirect_uri is pre-registred and should match");
+ }
+ redirectUri = client.getRedirectUri();
+ params.putSingle("resolved_redirect_uri", redirectUri);
+ } else {
+ if (redirectUri == null || redirectUri.isEmpty()) {
+ return informUserAboutError(request, response, "redirect_uri is not pre-registred and should be provided");
+ }
+ params.putSingle("resolved_redirect_uri", redirectUri);
+ }
+ request.setAttribute("client", client);
+
+ //4. response_type
+ String responseType = params.getFirst("response_type");
+ if (!"code".equals(responseType) && !"token".equals(responseType)) {
+ //error = "invalid_grant :" + responseType + ", response_type params should be code or token:";
+ //return informUserAboutError(error);
+ }
+
+ //Save params in session
+ request.getSession().setAttribute("ORIGINAL_PARAMS", params);
+
+ //4.scope: Optional
+ String requestedScope = request.getParameter("scope");
+ if (requestedScope == null || requestedScope.isEmpty()) {
+ requestedScope = client.getScope();
+ }
+ User user = appDataRepository.getUser(principal.getName());
+ String allowedScopes = checkUserScopes(user.getScopes(), requestedScope);
+ request.setAttribute("scopes", allowedScopes);
+
+ request.getRequestDispatcher("/authorize.jsp").forward(request, response);
+ return null;
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.TEXT_HTML)
+ public Response doPost(@Context HttpServletRequest request,
+ @Context HttpServletResponse response,
+ MultivaluedMap params) throws Exception {
+ MultivaluedMap originalParams = (MultivaluedMap) request.getSession().getAttribute("ORIGINAL_PARAMS");
+ if (originalParams == null) {
+ return informUserAboutError(request, response, "No pending authorization request.");
+ }
+ String redirectUri = originalParams.getFirst("resolved_redirect_uri");
+ StringBuilder sb = new StringBuilder(redirectUri);
+
+ String approbationStatus = params.getFirst("approbation_status");
+ if ("NO".equals(approbationStatus)) {
+ URI location = UriBuilder.fromUri(sb.toString())
+ .queryParam("error", "User doesn't approved the request.")
+ .queryParam("error_description", "User doesn't approved the request.")
+ .build();
+ return Response.seeOther(location).build();
+ }
+ //==> YES
+ List approvedScopes = params.get("scope");
+ if (approvedScopes == null || approvedScopes.isEmpty()) {
+ URI location = UriBuilder.fromUri(sb.toString())
+ .queryParam("error", "User doesn't approved the request.")
+ .queryParam("error_description", "User doesn't approved the request.")
+ .build();
+ return Response.seeOther(location).build();
+ }
+
+ String responseType = originalParams.getFirst("response_type");
+ String clientId = originalParams.getFirst("client_id");
+ if ("code".equals(responseType)) {
+ String userId = securityContext.getCallerPrincipal().getName();
+ AuthorizationCode authorizationCode = new AuthorizationCode();
+ authorizationCode.setClientId(clientId);
+ authorizationCode.setUserId(userId);
+ authorizationCode.setApprovedScopes(String.join(" ", approvedScopes));
+ authorizationCode.setExpirationDate(LocalDateTime.now().plusMinutes(10));
+ authorizationCode.setRedirectUri(redirectUri);
+ appDataRepository.save(authorizationCode);
+ String code = authorizationCode.getCode();
+ sb.append("?code=").append(code);
+ } else {
+ //Implicit: responseType=token
+ AuthorizationGrantTypeHandler authorizationGrantTypeHandler = authorizationGrantTypeHandlers.select(NamedLiteral.of("implicit")).get();
+ JsonObject tokenResponse = authorizationGrantTypeHandler.createAccessToken(clientId, params);
+ sb.append("#access_token=").append(tokenResponse.getString("access_token"))
+ .append("&token_type=").append(tokenResponse.getString("token_type"))
+ .append("&scope=").append(tokenResponse.getString("scope"));
+ }
+ String state = originalParams.getFirst("state");
+ if (state != null) {
+ sb.append("&state=").append(state);
+ }
+ return Response.seeOther(UriBuilder.fromUri(sb.toString()).build()).build();
+ }
+
+ private String checkUserScopes(String userScopes, String requestedScope) {
+ Set allowedScopes = new LinkedHashSet<>();
+ Set rScopes = new HashSet(Arrays.asList(requestedScope.split(" ")));
+ Set uScopes = new HashSet(Arrays.asList(userScopes.split(" ")));
+ for (String scope : uScopes) {
+ if (rScopes.contains(scope)) allowedScopes.add(scope);
+ }
+ return String.join(" ", allowedScopes);
+ }
+
+ private Response informUserAboutError(HttpServletRequest request, HttpServletResponse response, String error) throws ServletException, IOException {
+ request.setAttribute("error", error);
+ request.getRequestDispatcher("/error.jsp").forward(request, response);
+ return null;
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/JWKEndpoint.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/JWKEndpoint.java
new file mode 100644
index 0000000000..9d38c823b9
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/JWKEndpoint.java
@@ -0,0 +1,38 @@
+package com.baeldung.oauth2.authorization.server.api;
+
+import com.baeldung.oauth2.authorization.server.PEMKeyUtils;
+import com.nimbusds.jose.jwk.JWK;
+import org.eclipse.microprofile.config.Config;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Arrays;
+
+@Path("jwk")
+@ApplicationScoped
+public class JWKEndpoint {
+
+ @Inject
+ private Config config;
+
+ @GET
+ public Response getKey(@QueryParam("format") String format) throws Exception {
+ if (format != null && !Arrays.asList("jwk", "pem").contains(format)) {
+ return Response.status(Response.Status.BAD_REQUEST).entity("Public Key Format should be : jwk or pem").build();
+ }
+ String verificationkey = config.getValue("verificationkey", String.class);
+ String pemEncodedRSAPublicKey = PEMKeyUtils.readKeyAsString(verificationkey);
+ if (format == null || format.equals("jwk")) {
+ JWK jwk = JWK.parseFromPEMEncodedObjects(pemEncodedRSAPublicKey);
+ return Response.ok(jwk.toJSONString()).type(MediaType.APPLICATION_JSON).build();
+ } else if (format.equals("pem")) {
+ return Response.ok(pemEncodedRSAPublicKey).build();
+ }
+ return null;
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/TokenEndpoint.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/TokenEndpoint.java
new file mode 100644
index 0000000000..f39bb2ea2d
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/api/TokenEndpoint.java
@@ -0,0 +1,86 @@
+package com.baeldung.oauth2.authorization.server.api;
+
+import com.baeldung.oauth2.authorization.server.handler.AuthorizationGrantTypeHandler;
+import com.baeldung.oauth2.authorization.server.model.AppDataRepository;
+import com.baeldung.oauth2.authorization.server.model.Client;
+import com.nimbusds.jose.JOSEException;
+
+import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.literal.NamedLiteral;
+import javax.inject.Inject;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.ws.rs.*;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+@Path("token")
+public class TokenEndpoint {
+
+ List supportedGrantTypes = Collections.singletonList("authorization_code");
+
+ @Inject
+ private AppDataRepository appDataRepository;
+
+ @Inject
+ Instance authorizationGrantTypeHandlers;
+
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response token(MultivaluedMap params,
+ @HeaderParam(HttpHeaders.AUTHORIZATION) String authHeader) throws JOSEException {
+
+ //Check grant_type params
+ String grantType = params.getFirst("grant_type");
+ Objects.requireNonNull(grantType, "grant_type params is required");
+ if (!supportedGrantTypes.contains(grantType)) {
+ JsonObject error = Json.createObjectBuilder()
+ .add("error", "unsupported_grant_type")
+ .add("error_description", "grant type should be one of :" + supportedGrantTypes)
+ .build();
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity(error).build();
+
+ }
+
+ //Client Authentication
+ String[] clientCredentials = extract(authHeader);
+ String clientId = clientCredentials[0];
+ String clientSecret = clientCredentials[1];
+ Client client = appDataRepository.getClient(clientId);
+ if (client == null || clientSecret == null || !clientSecret.equals(client.getClientSecret())) {
+ JsonObject error = Json.createObjectBuilder()
+ .add("error", "invalid_client")
+ .build();
+ return Response.status(Response.Status.UNAUTHORIZED)
+ .entity(error).build();
+ }
+
+ AuthorizationGrantTypeHandler authorizationGrantTypeHandler = authorizationGrantTypeHandlers.select(NamedLiteral.of(grantType)).get();
+ JsonObject tokenResponse = null;
+ try {
+ tokenResponse = authorizationGrantTypeHandler.createAccessToken(clientId, params);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return Response.ok(tokenResponse)
+ .header("Cache-Control", "no-store")
+ .header("Pragma", "no-cache")
+ .build();
+ }
+
+ private String[] extract(String authHeader) {
+ if (authHeader != null && authHeader.startsWith("Basic ")) {
+ return new String(Base64.getDecoder().decode(authHeader.substring(6))).split(":");
+ }
+ return null;
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/handler/AuthorizationCodeGrantTypeHandler.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/handler/AuthorizationCodeGrantTypeHandler.java
new file mode 100644
index 0000000000..889c7fcea2
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/handler/AuthorizationCodeGrantTypeHandler.java
@@ -0,0 +1,99 @@
+package com.baeldung.oauth2.authorization.server.handler;
+
+import com.baeldung.oauth2.authorization.server.PEMKeyUtils;
+import com.baeldung.oauth2.authorization.server.model.AuthorizationCode;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.crypto.RSASSASigner;
+import com.nimbusds.jose.jwk.JWK;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import org.eclipse.microprofile.config.Config;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MultivaluedMap;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.UUID;
+
+@Named("authorization_code")
+public class AuthorizationCodeGrantTypeHandler implements AuthorizationGrantTypeHandler {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Inject
+ private Config config;
+
+ @Override
+ public JsonObject createAccessToken(String clientId, MultivaluedMap params) throws Exception {
+ //1. code is required
+ String code = params.getFirst("code");
+ if (code == null || "".equals(code)) {
+ throw new WebApplicationException("invalid_grant");
+ }
+ AuthorizationCode authorizationCode = entityManager.find(AuthorizationCode.class, code);
+ if (!authorizationCode.getExpirationDate().isAfter(LocalDateTime.now())) {
+ throw new WebApplicationException("code Expired !");
+ }
+ String redirectUri = params.getFirst("redirect_uri");
+ //redirecturi match
+ if (authorizationCode.getRedirectUri() != null && !authorizationCode.getRedirectUri().equals(redirectUri)) {
+ //redirectUri params should be the same as the requested redirectUri.
+ throw new WebApplicationException("invalid_grant");
+ }
+ //client match
+ if (!clientId.equals(authorizationCode.getClientId())) {
+ throw new WebApplicationException("invalid_grant");
+ }
+
+ //JWT Header
+ JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT).build();
+
+ Instant now = Instant.now();
+ Long expiresInMin = 30L;
+ Date expiresIn = Date.from(now.plus(expiresInMin, ChronoUnit.MINUTES));
+
+ //3. JWT Payload or claims
+ JWTClaimsSet jwtClaims = new JWTClaimsSet.Builder()
+ .issuer("http://localhost:9080")
+ .subject(authorizationCode.getUserId())
+ .claim("upn", authorizationCode.getUserId())
+ .audience("http://localhost:9280")
+ .claim("scope", authorizationCode.getApprovedScopes())
+ .claim("groups", Arrays.asList(authorizationCode.getApprovedScopes().split(" ")))
+ .expirationTime(expiresIn) // expires in 30 minutes
+ .notBeforeTime(Date.from(now))
+ .issueTime(Date.from(now))
+ .jwtID(UUID.randomUUID().toString())
+ .build();
+ SignedJWT signedJWT = new SignedJWT(jwsHeader, jwtClaims);
+
+ //4. Signing
+ String signingkey = config.getValue("signingkey", String.class);
+ String pemEncodedRSAPrivateKey = PEMKeyUtils.readKeyAsString(signingkey);
+ RSAKey rsaKey = (RSAKey) JWK.parseFromPEMEncodedObjects(pemEncodedRSAPrivateKey);
+ signedJWT.sign(new RSASSASigner(rsaKey.toRSAPrivateKey()));
+
+ //5. Finally the JWT access token
+ String accessToken = signedJWT.serialize();
+
+ return Json.createObjectBuilder()
+ .add("token_type", "Bearer")
+ .add("access_token", accessToken)
+ .add("expires_in", expiresInMin * 60)
+ .add("scope", authorizationCode.getApprovedScopes())
+ .build();
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/handler/AuthorizationGrantTypeHandler.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/handler/AuthorizationGrantTypeHandler.java
new file mode 100644
index 0000000000..a5afe293ef
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/handler/AuthorizationGrantTypeHandler.java
@@ -0,0 +1,8 @@
+package com.baeldung.oauth2.authorization.server.handler;
+
+import javax.json.JsonObject;
+import javax.ws.rs.core.MultivaluedMap;
+
+public interface AuthorizationGrantTypeHandler {
+ JsonObject createAccessToken(String clientId, MultivaluedMap params) throws Exception;
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/AppDataRepository.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/AppDataRepository.java
new file mode 100644
index 0000000000..6b827d6a3d
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/AppDataRepository.java
@@ -0,0 +1,27 @@
+package com.baeldung.oauth2.authorization.server.model;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.transaction.Transactional;
+
+@ApplicationScoped
+public class AppDataRepository {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ public Client getClient(String clientId) {
+ return entityManager.find(Client.class, clientId);
+ }
+
+ public User getUser(String userId) {
+ return entityManager.find(User.class, userId);
+ }
+
+ @Transactional
+ public AuthorizationCode save(AuthorizationCode authorizationCode) {
+ entityManager.persist(authorizationCode);
+ return authorizationCode;
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/AuthorizationCode.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/AuthorizationCode.java
new file mode 100644
index 0000000000..a2ec088eb9
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/AuthorizationCode.java
@@ -0,0 +1,73 @@
+package com.baeldung.oauth2.authorization.server.model;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "authorization_code")
+public class AuthorizationCode {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ @Column(name = "code")
+ private String code;
+ @Column(name = "client_id")
+ private String clientId;
+ @Column(name = "user_id")
+ private String userId;
+ @Column(name = "approved_scopes")
+ private String approvedScopes;
+
+ @Column(name = "redirect_uri")
+ private String redirectUri;
+
+ @Column(name = "expiration_date")
+ private LocalDateTime expirationDate;
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String username) {
+ this.userId = username;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getApprovedScopes() {
+ return approvedScopes;
+ }
+
+ public void setApprovedScopes(String approvedScopes) {
+ this.approvedScopes = approvedScopes;
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public void setRedirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ }
+
+ public LocalDateTime getExpirationDate() {
+ return expirationDate;
+ }
+
+ public void setExpirationDate(LocalDateTime expirationDate) {
+ this.expirationDate = expirationDate;
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/Client.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/Client.java
new file mode 100644
index 0000000000..9b5ad2f904
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/Client.java
@@ -0,0 +1,62 @@
+package com.baeldung.oauth2.authorization.server.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "clients")
+public class Client {
+ @Id
+ @Column(name = "client_id")
+ private String clientId;
+ @Column(name = "client_secret")
+ private String clientSecret;
+ @Column(name = "redirect_uri")
+ private String redirectUri;
+ @Column(name = "scope")
+ private String scope;
+ @Column(name = "authorized_grant_types")
+ private String authorizedGrantTypes;
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getClientSecret() {
+ return clientSecret;
+ }
+
+ public void setClientSecret(String clientSecret) {
+ this.clientSecret = clientSecret;
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public void setRedirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
+ public String getAuthorizedGrantTypes() {
+ return authorizedGrantTypes;
+ }
+
+ public void setAuthorizedGrantTypes(String authorizedGrantTypes) {
+ this.authorizedGrantTypes = authorizedGrantTypes;
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/User.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/User.java
new file mode 100644
index 0000000000..b3821715f4
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/model/User.java
@@ -0,0 +1,58 @@
+package com.baeldung.oauth2.authorization.server.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.security.Principal;
+
+@Entity
+@Table(name = "users")
+public class User implements Principal {
+ @Id
+ @Column(name = "user_id")
+ private String userId;
+ @Column(name = "password")
+ private String password;
+ @Column(name = "roles")
+ private String roles;
+ @Column(name = "scopes")
+ private String scopes;
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String username) {
+ this.userId = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getRoles() {
+ return roles;
+ }
+
+ public void setRoles(String roles) {
+ this.roles = roles;
+ }
+
+ public String getScopes() {
+ return scopes;
+ }
+
+ public void setScopes(String scopes) {
+ this.scopes = scopes;
+ }
+
+ @Override
+ public String getName() {
+ return getUserId();
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/security/UserIdentityStore.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/security/UserIdentityStore.java
new file mode 100644
index 0000000000..a32ab32cd4
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/security/UserIdentityStore.java
@@ -0,0 +1,37 @@
+package com.baeldung.oauth2.authorization.server.security;
+
+import com.baeldung.oauth2.authorization.server.model.AppDataRepository;
+import com.baeldung.oauth2.authorization.server.model.User;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.security.enterprise.credential.Credential;
+import javax.security.enterprise.credential.UsernamePasswordCredential;
+import javax.security.enterprise.identitystore.CredentialValidationResult;
+import javax.security.enterprise.identitystore.IdentityStore;
+import javax.transaction.Transactional;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Objects;
+
+import static javax.security.enterprise.identitystore.CredentialValidationResult.INVALID_RESULT;
+
+@ApplicationScoped
+@Transactional
+public class UserIdentityStore implements IdentityStore {
+
+ @Inject
+ private AppDataRepository appDataRepository;
+
+ @Override
+ public CredentialValidationResult validate(Credential credential) {
+ UsernamePasswordCredential usernamePasswordCredential = (UsernamePasswordCredential) credential;
+ String userId = usernamePasswordCredential.getCaller();
+ User user = appDataRepository.getUser(userId);
+ Objects.requireNonNull(user, "User should be not null");
+ if (usernamePasswordCredential.getPasswordAsString().equals(user.getPassword())) {
+ return new CredentialValidationResult(userId, new HashSet<>(Arrays.asList(user.getRoles().split(","))));
+ }
+ return INVALID_RESULT;
+ }
+}
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/web/AuthorizationEndpoint.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/web/AuthorizationEndpoint.java
new file mode 100644
index 0000000000..84b9a89c54
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/web/AuthorizationEndpoint.java
@@ -0,0 +1,209 @@
+//package com.baeldung.security.oauth2.server.web;
+//
+//import AuthorizationCode;
+//import Client;
+//import User;
+//import com.baeldung.security.oauth2.server.service.AuthCodeService;
+//
+//import javax.ejb.EJB;
+//import javax.enterprise.context.RequestScoped;
+//import javax.inject.Inject;
+//import javax.persistence.EntityManager;
+//import javax.persistence.PersistenceContext;
+//import javax.security.enterprise.SecurityContext;
+//import javax.security.enterprise.authentication.mechanism.http.FormAuthenticationMechanismDefinition;
+//import javax.security.enterprise.authentication.mechanism.http.LoginToContinue;
+//import javax.servlet.ServletException;
+//import javax.servlet.annotation.HttpConstraint;
+//import javax.servlet.annotation.ServletSecurity;
+//import javax.servlet.annotation.WebServlet;
+//import javax.servlet.http.HttpServlet;
+//import javax.servlet.http.HttpServletRequest;
+//import javax.servlet.http.HttpServletResponse;
+//import java.io.IOException;
+//import java.security.Principal;
+//import java.util.*;
+//
+///**
+// * 1. GET http://localhost:8080/app/ (302)
+// * 2. GET http://localhost:8080/uaa/authorize?client_id=app&redirect_uri=http://localhost:8080/app/&response_type=code&state=A123 (302)
+// * 3. GET http://localhost:8080/uaa/login (200) with initial request as hidden input
+// * 4. POST http://localhost:8080/uaa/login (username, password, initial client request) (302)
+// * 5. GET http://localhost:8080/uaa/authorize?client_id=app&redirect_uri=http://localhost:8080/app/&response_type=code&state=A123 (200)
+// * 7. POST http://localhost:8080/uaa/authorize?client_id=app&redirect_uri=http://localhost:8080/app/&response_type=code&state=A123 (302)
+// * 8. GET http://localhost:8080/app/?code=rkWijq06mL&state=A123 (200)
+// */
+///*
+//
+//Query Params:
+// client_id: app
+// redirect_uri: http://localhost:8080/app/
+// response_type: code
+// state: A123
+//
+// ==> GET user login WITH client request as hidden input:
+//
+//
+// ==> After user login ==> Initial client request
+// ==> gen code
+// == redirect to redirect uri + params code & state : 302, location : http://localhost:8080/app/?code=w6A0YQFzzg&state=A123
+//*/
+//
+////authorize?client_id=app&redirect_uri=http://localhost:8080/app/&response_type=code&state=A123
+////http://localhost:9080/authorize?response_type=code&client_id=client_id_1&redirect_uri=http://localhost:9080/app&state=A123
+//
+////@RequestScoped
+//@FormAuthenticationMechanismDefinition(
+// loginToContinue = @LoginToContinue(
+// loginPage = "/login-servlet",
+// errorPage = "/login-error-servlet"
+// )
+//)
+//@WebServlet({"/authorize"})
+//@ServletSecurity(@HttpConstraint(rolesAllowed = "user"))
+////@Stateless
+//@RequestScoped
+//public class AuthorizationEndpoint extends HttpServlet {
+//
+// private static final List authorizedResponseTypes = Arrays.asList("code", "token");
+//
+// @Inject
+// private SecurityContext securityContext;
+//
+// @PersistenceContext(name = "jpa-oauth2-pu")
+// private EntityManager entityManager;
+//
+// @EJB
+// private AuthCodeService authCodeService;
+//
+// //HTTP GET IS A MUST, POST IS OPTIONAL
+// @Override
+// protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+//
+// String error = "";
+//
+// //1. User Authentication
+// Principal principal = securityContext.getCallerPrincipal();
+//
+// //2. Check for a valid client_id
+// String clientId = request.getParameter("client_id");
+// if (clientId == null) {
+// request.setAttribute("error", "The client " + clientId + " doesn't exist.");
+// }
+// request.setAttribute("clientId", clientId);
+// Client client = entityManager.find(Client.class, clientId);
+// if (client == null) {
+// request.setAttribute("error", "The client " + clientId + " doesn't exist.");
+// }
+//
+// //3. check for a valid response_type
+// String responseType = request.getParameter("response_type");
+// if (!authorizedResponseTypes.contains(responseType)) {
+// error = "invalid_grant :" + responseType + ", response_type params should be one of :" + authorizedResponseTypes;
+// request.setAttribute("error", error);
+// request.getRequestDispatcher("/error.jsp")
+// .forward(request, response);
+// }
+//
+// //4. Optional redirect_uri, if provided should match
+// String redirectUri = request.getParameter("redirect_uri");
+// checkRedirectUri(client, redirectUri);
+//
+// //save params
+// String currentUri = request.getRequestURI();
+// request.setAttribute("post_redirect_uri", currentUri);
+//
+// String state = request.getParameter("state");
+// Map requestMap = new HashMap<>();
+// requestMap.put("response_type", responseType);
+// requestMap.put("client_id", clientId);
+// requestMap.put("redirect_uri", redirectUri);
+// requestMap.put("state", state);
+// request.setAttribute("requestMap", requestMap);
+//
+// //5.scope: Optional
+// String requestedScope = request.getParameter("scope");
+// if (requestedScope.isEmpty()) {
+// requestedScope = client.getScope();
+// }
+// //requestedScope should be a subset of the client scope: clientScopes.containsAll(requestedScopes)
+// //checkRequestedScope(requestedScope, client.getScope());
+//
+// //sub set of user scope
+// //allowed scope by the user
+//
+// User user = entityManager.find(User.class, principal.getName());
+// request.setAttribute("scopes", requestedScope);
+//
+//
+// forward("/authorize.jsp", request, response);
+// }
+//
+// @Override
+// protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+// String clientId = request.getParameter("client_id");
+//
+// String responseType = request.getParameter("response_type");
+// if (!authorizedResponseTypes.contains(responseType)) {
+// String error = "invalid_grant :" + responseType + ", response_type params should be one of :" + authorizedResponseTypes;
+// request.setAttribute("error", error);
+// forward("/error.jsp", request, response);
+// }
+//
+// Client client = entityManager.find(Client.class, clientId);
+// Objects.requireNonNull(client);
+//
+// String userId = securityContext.getCallerPrincipal().getName();
+// AuthorizationCode authorizationCode = new AuthorizationCode();
+// authorizationCode.setClientId(clientId);
+// authorizationCode.setUserId(userId);
+// String redirectUri = request.getParameter("redirect_uri");
+// authorizationCode.setRedirectUri(redirectUri);
+//
+// redirectUri = checkRedirectUri(client, redirectUri);
+//
+// String[] scope = request.getParameterValues("scope");
+// if (scope == null) {
+// request.setAttribute("error", "User doesn't approved any scope");
+// forward("/error.jsp", request, response);
+// }
+//
+// String approvedScopes = String.join(" ", scope);
+// authorizationCode.setApprovedScopes(approvedScopes);
+//
+// //entityManager.persist(authorizationCode);
+// authCodeService.save(authorizationCode);
+// String code = authorizationCode.getCode();
+//
+// StringBuilder sb = new StringBuilder(redirectUri);
+// sb.append("?code=").append(code);
+//
+// //If the client send a state, Send it back
+// String state = request.getParameter("state");
+// if (state != null) {
+// sb.append("&state=").append(state);
+// }
+// response.sendRedirect(sb.toString());
+// }
+//
+// private String checkRedirectUri(Client client, String redirectUri) {
+// //redirect uri
+// if (redirectUri == null) {
+// //erreur: param redirect_uri && client redirect_uri don't match.
+// redirectUri = client.getRedirectUri();
+// if (redirectUri == null) {
+// throw new IllegalStateException("redirectUri shloud be not null, unless a registred client have a redirect_uri.");
+// }
+// } else if (!redirectUri.equals(client.getRedirectUri())) {
+// throw new IllegalStateException("request redirectUri and client registred redirect_uri should match.");
+// }
+// return redirectUri;
+// }
+//
+// private void forward(String path, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+// request.getRequestDispatcher(path)
+// .forward(request, response);
+// }
+//}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/web/TokenEndpoint.java b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/web/TokenEndpoint.java
new file mode 100644
index 0000000000..73085a68d1
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/java/com/baeldung/oauth2/authorization/server/web/TokenEndpoint.java
@@ -0,0 +1,70 @@
+//package com.baeldung.security.oauth2.server.web;
+//
+//import AuthorizationGrantTypeHandler;
+//import TokenResponse;
+//import com.baeldung.security.oauth2.server.security.Authenticated;
+//import com.nimbusds.jose.JOSEException;
+//
+//import javax.enterprise.inject.Instance;
+//import javax.enterprise.inject.literal.NamedLiteral;
+//import javax.inject.Inject;
+//import javax.security.enterprise.SecurityContext;
+//import javax.ws.rs.Consumes;
+//import javax.ws.rs.POST;
+//import javax.ws.rs.Path;
+//import javax.ws.rs.Produces;
+//import javax.ws.rs.core.MediaType;
+//import javax.ws.rs.core.MultivaluedMap;
+//import javax.ws.rs.core.Response;
+//import java.security.Principal;
+//import java.util.Arrays;
+//import java.util.List;
+//import java.util.Objects;
+//
+///**
+// * {
+// * "access_token" : "acb6803a48114d9fb4761e403c17f812",
+// * "token_type" : "bearer",
+// * "id_token" : "eyJhbGciOiJIUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAvdWFhL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.eyJzdWIiOiIwNzYzZTM2MS02ODUwLTQ3N2ItYjk1Ny1iMmExZjU3MjczMTQiLCJhdWQiOlsibG9naW4iXSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3VhYS9vYXV0aC90b2tlbiIsImV4cCI6MTU1NzgzMDM4NSwiaWF0IjoxNTU3Nzg3MTg1LCJhenAiOiJsb2dpbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJlbWFpbCI6IndyaHBONUB0ZXN0Lm9yZyIsInppZCI6InVhYSIsIm9yaWdpbiI6InVhYSIsImp0aSI6ImFjYjY4MDNhNDgxMTRkOWZiNDc2MWU0MDNjMTdmODEyIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImNsaWVudF9pZCI6ImxvZ2luIiwiY2lkIjoibG9naW4iLCJncmFudF90eXBlIjoiYXV0aG9yaXphdGlvbl9jb2RlIiwidXNlcl9uYW1lIjoid3JocE41QHRlc3Qub3JnIiwicmV2X3NpZyI6ImI3MjE5ZGYxIiwidXNlcl9pZCI6IjA3NjNlMzYxLTY4NTAtNDc3Yi1iOTU3LWIyYTFmNTcyNzMxNCIsImF1dGhfdGltZSI6MTU1Nzc4NzE4NX0.Fo8wZ_Zq9mwFks3LfXQ1PfJ4ugppjWvioZM6jSqAAQQ",
+// * "refresh_token" : "f59dcb5dcbca45f981f16ce519d61486-r",
+// * "expires_in" : 43199,
+// * "scope" : "openid oauth.approvals",
+// * "jti" : "acb6803a48114d9fb4761e403c17f812"
+// * }
+// */
+//@Path("token")
+//public class TokenEndpoint {
+//
+// List supportedGrantTypes = Arrays.asList("authorization_code", "password", "refresh_token", "client_credentials");
+//
+// @Inject
+// private SecurityContext securityContext;
+//
+// @Inject
+// Instance authorizationGrantTypeHandlers;
+//
+// @POST
+// @Produces(MediaType.APPLICATION_JSON)
+// @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+// @Authenticated
+// public Response token(MultivaluedMap params) throws JOSEException {
+// //Authenticate client with [basic] http authentication mechanism
+// Principal principal = securityContext.getCallerPrincipal();
+// Objects.requireNonNull(principal, "Client not authenticated!");
+//
+// //Check grant_type params
+// String grantType = params.getFirst("grant_type");
+// Objects.requireNonNull(grantType, "grant_type params is required");
+// //authorization_code, password, refresh, client_credentials
+// if (!supportedGrantTypes.contains(grantType)) {
+// throw new RuntimeException("grant_type parameter should be one of the following :" + supportedGrantTypes);
+// }
+// AuthorizationGrantTypeHandler authorizationGrantTypeHandler = authorizationGrantTypeHandlers.select(NamedLiteral.of(grantType)).get();
+// TokenResponse tokenResponse = authorizationGrantTypeHandler.createAccessToken(principal.getName(), params);
+// Response response = Response.ok(tokenResponse)
+// .header("Cache-Control", "no-store")
+// .header("Pragma", "no-cache")
+// .build();
+// return response;
+// }
+//}
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/liberty/config/server.xml b/oauth2-framework-impl/oauth2-authorization-server/src/main/liberty/config/server.xml
new file mode 100644
index 0000000000..97d9ec4a28
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/liberty/config/server.xml
@@ -0,0 +1,32 @@
+
+
+
+
+ localConnector-1.0
+ cdi-2.0
+ jaxrs-2.1
+ jpa-2.2
+ appSecurity-3.0
+ jsp-2.3
+ mpConfig-1.3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/microprofile-config.properties b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/microprofile-config.properties
new file mode 100644
index 0000000000..d9c68bc111
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/microprofile-config.properties
@@ -0,0 +1,2 @@
+signingkey=/META-INF/private-key.pem
+verificationkey=/META-INF/public-key.pem
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/persistence.xml b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000000..a10ad3c886
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,14 @@
+
+
+
+ jdbc/OAuth2_DS
+
+
+
+
+
+
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/private-key.pem b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/private-key.pem
new file mode 100644
index 0000000000..6e36cb4d78
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/private-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDYizUyvwY6qMd0
+ZkYPzP9mLTJOSczW8WtAbjhrgxk5LORIjcdv/aB1BAzDEOCX4UC+Rbs9YwaekIvW
+7dL/t6xPzsA7+9tMt27TqUxXigWEFQG73w/WbEVzCG09IHqG7Ztjb6aGL+8pfcu+
+SLvOtXWrctHNbr35BYC5yBQaos9bH+nLYbh2Ff+emrpg7Kwoeis6MY6RgZIL/lxt
+3beZt1NQhLEvB9t6XoSkyLQKSjT/OC8XOa4OYI4OfOSFqEUEp+8dKe3svZbQUNJf
+KKehx78xx0rfwH+iBsFKkHdvt1ZHtINvYedAfGrc5rWnesunzOW7OKMAiIXAJSRA
+rn9Iv5/fAgMBAAECggEAYHKwgSfAGIRwQhIDhqoh31qmG2SXjez9fjcZfhloNKUg
+EIjFmcX3n+br4D42Kq+zbIwWd6MRobJz9oj6/9bJMsq9qHnnFWZmQHQZgqwBBPFu
+UkVqAnE7BZ9tOFqs+EgAe+uQ2hejiHF1PA2dSNZd0L1VYRDAIJgo25aYDb0Sal0c
+qaFmK1XzPnSIhgnopKP/TmUfALjeshtGvh6WkiXHTY2VKJlyLEiGd3/1tBZnzwSQ
+QiS/2zfXL7lO0SYRA10m1BmtqGi3wSKIXUA6tNulmpXEMnYk4RtsqBClOanzQIm7
+f4Ie59AtUUlDdHzRmhxBaDprgAI/FdCxXkseLzk5sQKBgQDyptOhJ/VQ5tkgffJW
+X2QwGIaNdvNCEL4GlgXKAWNkCzT4h+Q/2wFoKhaN2JH2YZwKCRwG/UZh4Hq22fdx
+fa/DP8PK3zlX0c9dWQOtmBOe0/nG28kq9iqziP3ILLNuelfaMhxtRkUmR652VCzx
+qazZmjoo2MxtA6BMiK3Vx5aikwKBgQDkdLalVveHKTVkrplQYNapQAtAwjlsNnMt
+VJh6nLo3eOg1xBNA7JrYqx7sXRQInUGAyNKvgQL/lCQdMkTzyetLjJGsiFSEgeot
+RMsDXBrJFYZiErbpQungpaevwAymaGi++nbCzhw1/n3AvVUhRKNknX8Ms0UKlLRZ
+TCktCTChBQKBgGA7ZzzHgxPFqaCoMl6s0Cf+4gXigdDWoPYtszgM2uUHSMez5QKq
+EWHFJ1Kz7BdBWMfmGvZupeYVR7WStf6NcRJHDJg9dRlt/QYxUjMbV9Sqjqmd6qce
+H4s6LiOgDr0mygafzwRLVQs8bGVDNtvUhdd6wcwHRvOI957CqeZZlFT/AoGBAN2P
+j79EW6U6wuyVJF0+vZDBauhwNQ6MtCEnZQWs0DCSUuop8d5KWVZ+huwGzTIZiPhk
+S2goP4cs3eVu5k5k6oyHlJP2V7l24WzrxdPJVLTl6kFdEwWgfn//SGR7ZglRQxzM
+fbcp+1QmL0FonZI5JhmjYR8pEXFUjJ/57AkgW4gdAoGASV3TlaNd+reb2l0kETqp
+HrzzMIYkM2faZ8LmpcEO0wz606SK468bnl6SqVBYT2J0bkqCpEmPBtWs/OFCWd6x
+93NndSfJk57/7AqNxfVyZWp2sjRzt5vZ4KPlRVvMHIGeJNbIV7RqUr6XGu+u3ZrS
+B7SqwKZqdHVSULG9nMK7Iz8=
+-----END PRIVATE KEY-----
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/public-key.pem b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/public-key.pem
new file mode 100644
index 0000000000..f53ceca446
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/META-INF/public-key.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Is1Mr8GOqjHdGZGD8z/
+Zi0yTknM1vFrQG44a4MZOSzkSI3Hb/2gdQQMwxDgl+FAvkW7PWMGnpCL1u3S/7es
+T87AO/vbTLdu06lMV4oFhBUBu98P1mxFcwhtPSB6hu2bY2+mhi/vKX3Lvki7zrV1
+q3LRzW69+QWAucgUGqLPWx/py2G4dhX/npq6YOysKHorOjGOkYGSC/5cbd23mbdT
+UISxLwfbel6EpMi0Cko0/zgvFzmuDmCODnzkhahFBKfvHSnt7L2W0FDSXyinoce/
+McdK38B/ogbBSpB3b7dWR7SDb2HnQHxq3Oa1p3rLp8zluzijAIiFwCUkQK5/SL+f
+3wIDAQAB
+-----END PUBLIC KEY-----
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/data.sql b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/data.sql
new file mode 100644
index 0000000000..ecda0fa2ad
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/resources/data.sql
@@ -0,0 +1,3 @@
+INSERT INTO `users` (`user_id`, `password`, `roles`, `scopes`) VALUES ('appuser', 'appusersecret', 'USER', 'resource.read resource.write');
+
+INSERT INTO `clients` (`client_id`, `client_secret`, `redirect_uri`,`scope`,`authorized_grant_types`) VALUES ('webappclient', 'webappclientsecret', 'http://localhost:9180/callback', 'resource.read resource.write', 'authorization_code refresh_token');
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/WEB-INF/beans.xml b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000000..29595ff490
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/authorize.jsp b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/authorize.jsp
new file mode 100644
index 0000000000..1004b5b8b7
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/authorize.jsp
@@ -0,0 +1,54 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+
+
+
+ Authorization
+
+
+
+
+
+
Want to Authorize scopes for client : ${client.clientId} ?
+
+
+
+
+
+
+
+
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/error.jsp b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/error.jsp
new file mode 100644
index 0000000000..edb0bf28b7
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/error.jsp
@@ -0,0 +1,25 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+
+
+
+
+
+ Error
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/login-error.jsp b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/login-error.jsp
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/login.jsp b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/login.jsp
new file mode 100644
index 0000000000..1d2dd93fd0
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-authorization-server/src/main/webapp/login.jsp
@@ -0,0 +1,49 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+
+
+
+
+ Login Form
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-client/pom.xml b/oauth2-framework-impl/oauth2-client/pom.xml
new file mode 100644
index 0000000000..e46a44268e
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+ oauth2-client
+ war
+
+
+ com.baeldung.oauth2
+ oauth2-framework-impl
+ 1.0-SNAPSHOT
+
+
+
+ 9180
+ 9543
+
+
+
+
+
+ net.wasdev.wlp.maven.plugins
+ liberty-maven-plugin
+
+
+
+
diff --git a/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/AuthorizationCodeServlet.java b/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/AuthorizationCodeServlet.java
new file mode 100644
index 0000000000..a5fdaf07f2
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/AuthorizationCodeServlet.java
@@ -0,0 +1,39 @@
+package com.baeldung.oauth2.client;
+
+import org.eclipse.microprofile.config.Config;
+
+import javax.inject.Inject;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.UUID;
+
+@WebServlet(urlPatterns = "/authorize")
+public class AuthorizationCodeServlet extends HttpServlet {
+
+ @Inject
+ private Config config;
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ //...
+ request.getSession().removeAttribute("tokenResponse");
+ String state = UUID.randomUUID().toString();
+ request.getSession().setAttribute("CLIENT_LOCAL_STATE", state);
+
+ String authorizationUri = config.getValue("provider.authorizationUri", String.class);
+ String clientId = config.getValue("client.clientId", String.class);
+ String redirectUri = config.getValue("client.redirectUri", String.class);
+ String scope = config.getValue("client.scope", String.class);
+
+ String authorizationLocation = authorizationUri + "?response_type=code"
+ + "&client_id=" + clientId
+ + "&redirect_uri=" + redirectUri
+ + "&scope=" + scope
+ + "&state=" + state;
+ response.sendRedirect(authorizationLocation);
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/CallbackServlet.java b/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/CallbackServlet.java
new file mode 100644
index 0000000000..87aa8bc668
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/CallbackServlet.java
@@ -0,0 +1,76 @@
+package com.baeldung.oauth2.client;
+
+import org.eclipse.microprofile.config.Config;
+
+import javax.inject.Inject;
+import javax.json.JsonObject;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.util.Base64;
+
+@WebServlet(urlPatterns = "/callback")
+public class CallbackServlet extends HttpServlet {
+
+ @Inject
+ private Config config;
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ //Error:
+ String error = request.getParameter("error");
+ if (error != null) {
+ request.setAttribute("error", error);
+ dispatch("/", request, response);
+ return;
+ }
+ String localState = (String) request.getSession().getAttribute("CLIENT_LOCAL_STATE");
+ if (!localState.equals(request.getParameter("state"))) {
+ request.setAttribute("error", "The state attribute doesn't match !!");
+ dispatch("/", request, response);
+ return;
+ }
+
+ String code = request.getParameter("code");
+
+ Client client = ClientBuilder.newClient();
+ WebTarget target = client.target(config.getValue("provider.tokenUri", String.class));
+
+ Form form = new Form();
+ form.param("grant_type", "authorization_code");
+ form.param("code", code);
+ form.param("redirect_uri", config.getValue("client.redirectUri", String.class));
+
+ JsonObject tokenResponse = target.request(MediaType.APPLICATION_JSON_TYPE)
+ .header(HttpHeaders.AUTHORIZATION, getAuthorizationHeaderValue())
+ .post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE), JsonObject.class);
+
+ request.getSession().setAttribute("tokenResponse", tokenResponse);
+ dispatch("/", request, response);
+ }
+
+ private void dispatch(String location, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ RequestDispatcher requestDispatcher = request.getRequestDispatcher(location);
+ requestDispatcher.forward(request, response);
+ }
+
+ private String getAuthorizationHeaderValue() {
+ String clientId = config.getValue("client.clientId", String.class);
+ String clientSecret = config.getValue("client.clientSecret", String.class);
+ String token = clientId + ":" + clientSecret;
+ String encodedString = Base64.getEncoder().encodeToString(token.getBytes());
+ return "Basic " + encodedString;
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/DownstreamCallServlet.java b/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/DownstreamCallServlet.java
new file mode 100644
index 0000000000..bbe850917b
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/src/main/java/com/baeldung/oauth2/client/DownstreamCallServlet.java
@@ -0,0 +1,49 @@
+package com.baeldung.oauth2.client;
+
+import org.eclipse.microprofile.config.Config;
+
+import javax.inject.Inject;
+import javax.json.JsonObject;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.*;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+@WebServlet(urlPatterns = "/downstream")
+public class DownstreamCallServlet extends HttpServlet {
+
+ @Inject
+ private Config config;
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
+ resp.setContentType("text/html;charset=UTF-8");
+ String action = request.getParameter("action");
+ Client client = ClientBuilder.newClient();
+ WebTarget webTarget = client.target(config.getValue("resourceServerUri", String.class));
+ WebTarget resourceWebTarget;
+ String response = null;
+ JsonObject tokenResponse = (JsonObject) request.getSession().getAttribute("tokenResponse");
+ if ("read".equals(action)) {
+ resourceWebTarget = webTarget.path("resource/read");
+ Invocation.Builder invocationBuilder = resourceWebTarget.request();
+ response = invocationBuilder
+ .header("authorization", tokenResponse.getString("access_token"))
+ .get(String.class);
+ } else if ("write".equals(action)) {
+ resourceWebTarget = webTarget.path("resource/write");
+ Invocation.Builder invocationBuilder = resourceWebTarget.request();
+ response = invocationBuilder
+ .header("authorization", tokenResponse.getString("access_token"))
+ .post(Entity.text("body string"), String.class);
+ }
+ PrintWriter out = resp.getWriter();
+ out.println(response);
+ out.flush();
+ out.close();
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-client/src/main/liberty/config/server.xml b/oauth2-framework-impl/oauth2-client/src/main/liberty/config/server.xml
new file mode 100644
index 0000000000..26dc730361
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/src/main/liberty/config/server.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ localConnector-1.0
+ cdi-2.0
+ jsp-2.3
+ mpConfig-1.3
+ jaxrsClient-2.1
+ jsonp-1.1
+
+
+
+
+
+
+
+
+
diff --git a/oauth2-framework-impl/oauth2-client/src/main/resources/META-INF/microprofile-config.properties b/oauth2-framework-impl/oauth2-client/src/main/resources/META-INF/microprofile-config.properties
new file mode 100644
index 0000000000..d66f4f6a74
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/src/main/resources/META-INF/microprofile-config.properties
@@ -0,0 +1,12 @@
+#Client registration
+client.clientId=webappclient
+client.clientSecret=webappclientsecret
+client.redirectUri=http://localhost:9180/callback
+client.scope=resource.read resource.write
+
+#Provider
+provider.authorizationUri=http://127.0.0.1:9080/authorize
+provider.tokenUri=http://127.0.0.1:9080/token
+
+#Resource Server
+resourceServerUri=http://localhost:9280/api
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-client/src/main/webapp/WEB-INF/beans.xml b/oauth2-framework-impl/oauth2-client/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000000..29595ff490
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/oauth2-framework-impl/oauth2-client/src/main/webapp/WEB-INF/web.xml b/oauth2-framework-impl/oauth2-client/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..0203894c1b
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,5 @@
+
+
+ index.jsp
+
+
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-client/src/main/webapp/index.jsp b/oauth2-framework-impl/oauth2-client/src/main/webapp/index.jsp
new file mode 100644
index 0000000000..23fec70f33
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-client/src/main/webapp/index.jsp
@@ -0,0 +1,97 @@
+<%@ page import="org.eclipse.microprofile.config.Config" %>
+<%@ page import="org.eclipse.microprofile.config.ConfigProvider" %>
+
+
+
+
+
+ OAuth2 Client
+
+
+
+
+
+<%
+ Config config1 = ConfigProvider.getConfig();
+%>
+
+">
+ Error : ${error}
+
+
+
+
OAuth2 Authorization Server
+
+
Client Registration :
+
+ - client_id: <%=config1.getValue("client.clientId", String.class)%>
+
+ - client_secret: <%=config1.getValue("client.clientSecret", String.class)%>
+
+ - redirect_uri: <%=config1.getValue("client.redirectUri", String.class)%>
+
+ - scope: <%=config1.getValue("client.scope", String.class)%>
+
+
+
Authorization Server :
+
+ - authorization_uri: <%=config1.getValue("provider.authorizationUri", String.class)%>
+
+ - token_uri: <%=config1.getValue("provider.tokenUri", String.class)%>
+
+
+
+
+
OAuth2 Client
+
+
Token Request :
+
+
+
Token Response:
+
+ - access_token: ${tokenResponse.getString("access_token")}
+ - scope: ${tokenResponse.getString("scope")}
+ - Expires in (s): ${tokenResponse.getInt("expires_in")}
+
+
+
+
OAuth2 Resource Server Call
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-resource-server/pom.xml b/oauth2-framework-impl/oauth2-resource-server/pom.xml
new file mode 100644
index 0000000000..9b58c33472
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-resource-server/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+ oauth2-resource-server
+ war
+
+
+ com.baeldung.oauth2
+ oauth2-framework-impl
+ 1.0-SNAPSHOT
+
+
+
+ 9280
+ 8643
+ http://localhost:9080
+ http://localhost:9280
+
+
+
+
+ org.eclipse.microprofile.jwt
+ microprofile-jwt-auth-api
+ 1.1
+ provided
+
+
+
+
+
+
+ net.wasdev.wlp.maven.plugins
+ liberty-maven-plugin
+
+
+
+
+
diff --git a/oauth2-framework-impl/oauth2-resource-server/src/main/java/com/baeldung/oauth2/resource/server/OAuth2ResourceServerApplication.java b/oauth2-framework-impl/oauth2-resource-server/src/main/java/com/baeldung/oauth2/resource/server/OAuth2ResourceServerApplication.java
new file mode 100644
index 0000000000..835e80a416
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-resource-server/src/main/java/com/baeldung/oauth2/resource/server/OAuth2ResourceServerApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.oauth2.resource.server;
+
+import org.eclipse.microprofile.auth.LoginConfig;
+
+import javax.annotation.security.DeclareRoles;
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+@ApplicationPath("/api")
+@DeclareRoles({"resource.read", "resource.write"})
+@LoginConfig(authMethod = "MP-JWT")
+public class OAuth2ResourceServerApplication extends Application {
+}
diff --git a/oauth2-framework-impl/oauth2-resource-server/src/main/java/com/baeldung/oauth2/resource/server/secure/ProtectedResource.java b/oauth2-framework-impl/oauth2-resource-server/src/main/java/com/baeldung/oauth2/resource/server/secure/ProtectedResource.java
new file mode 100644
index 0000000000..300de83c6d
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-resource-server/src/main/java/com/baeldung/oauth2/resource/server/secure/ProtectedResource.java
@@ -0,0 +1,38 @@
+package com.baeldung.oauth2.resource.server.secure;
+
+import org.eclipse.microprofile.jwt.JsonWebToken;
+
+import javax.annotation.security.RolesAllowed;
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import java.util.UUID;
+
+@Path("/resource")
+@RequestScoped
+public class ProtectedResource {
+
+ @Inject
+ private JsonWebToken principal;
+
+ @GET
+ @RolesAllowed("resource.read")
+ @Path("/read")
+ public Response read() {
+ //DoStaff
+ return Response.ok("Hello, " + principal.getName()).build();
+ }
+
+ @POST
+ @RolesAllowed("resource.write")
+ @Path("/write")
+ public Response write() {
+ //DoStaff
+ return Response.ok("Hello, " + principal.getName())
+ .header("location", UUID.randomUUID().toString())
+ .build();
+ }
+}
diff --git a/oauth2-framework-impl/oauth2-resource-server/src/main/liberty/config/server.xml b/oauth2-framework-impl/oauth2-resource-server/src/main/liberty/config/server.xml
new file mode 100644
index 0000000000..c54d698359
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-resource-server/src/main/liberty/config/server.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ localConnector-1.0
+ cdi-2.0
+ jaxrs-2.1
+ jsonp-1.1
+ mpConfig-1.3
+ mpJwt-1.1
+
+
+
+
+
+
+
+
+
+
diff --git a/oauth2-framework-impl/oauth2-resource-server/src/main/resources/META-INF/microprofile-config.properties b/oauth2-framework-impl/oauth2-resource-server/src/main/resources/META-INF/microprofile-config.properties
new file mode 100644
index 0000000000..be6919ec50
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-resource-server/src/main/resources/META-INF/microprofile-config.properties
@@ -0,0 +1,2 @@
+mp.jwt.verify.publickey.location=/META-INF/public-key.pem
+mp.jwt.verify.issuer=http://localhost:9080
\ No newline at end of file
diff --git a/oauth2-framework-impl/oauth2-resource-server/src/main/resources/META-INF/public-key.pem b/oauth2-framework-impl/oauth2-resource-server/src/main/resources/META-INF/public-key.pem
new file mode 100644
index 0000000000..f53ceca446
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-resource-server/src/main/resources/META-INF/public-key.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Is1Mr8GOqjHdGZGD8z/
+Zi0yTknM1vFrQG44a4MZOSzkSI3Hb/2gdQQMwxDgl+FAvkW7PWMGnpCL1u3S/7es
+T87AO/vbTLdu06lMV4oFhBUBu98P1mxFcwhtPSB6hu2bY2+mhi/vKX3Lvki7zrV1
+q3LRzW69+QWAucgUGqLPWx/py2G4dhX/npq6YOysKHorOjGOkYGSC/5cbd23mbdT
+UISxLwfbel6EpMi0Cko0/zgvFzmuDmCODnzkhahFBKfvHSnt7L2W0FDSXyinoce/
+McdK38B/ogbBSpB3b7dWR7SDb2HnQHxq3Oa1p3rLp8zluzijAIiFwCUkQK5/SL+f
+3wIDAQAB
+-----END PUBLIC KEY-----
diff --git a/oauth2-framework-impl/oauth2-resource-server/src/main/webapp/WEB-INF/beans.xml b/oauth2-framework-impl/oauth2-resource-server/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000000..2777559c20
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-resource-server/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/oauth2-framework-impl/oauth2-resource-server/src/main/webapp/index.html b/oauth2-framework-impl/oauth2-resource-server/src/main/webapp/index.html
new file mode 100644
index 0000000000..7ea29c1097
--- /dev/null
+++ b/oauth2-framework-impl/oauth2-resource-server/src/main/webapp/index.html
@@ -0,0 +1,37 @@
+
+
+
+
+ Eclipse MicroProfile demo
+
+
+
+MicroProfile
+
+Hello JAX-RS endpoint
+
+
+Config
+Injected config values
+Config values by lookup
+
+
+
+
+
+
+
+
+
+JWT Auth
+Look at readme.md on how to test protected endpoint.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/oauth2-framework-impl/pom.xml b/oauth2-framework-impl/pom.xml
new file mode 100644
index 0000000000..281103660b
--- /dev/null
+++ b/oauth2-framework-impl/pom.xml
@@ -0,0 +1,93 @@
+
+
+ 4.0.0
+ com.baeldung.oauth2
+ oauth2-framework-impl
+ 1.0-SNAPSHOT
+ pom
+
+
+ 1.8
+ 1.8
+ false
+ RELEASE
+ 2.6.4
+
+
+
+
+ javax
+ javaee-web-api
+ 8.0
+ provided
+
+
+ org.eclipse.microprofile.config
+ microprofile-config-api
+ 1.3
+ provided
+
+
+
+
+ ${project.artifactId}
+
+
+ ${basedir}/src/main/resources
+
+ **/*.*
+
+
+
+ true
+ ${basedir}/src/main/liberty
+
+ **/*.*
+
+
+
+
+
+
+ net.wasdev.wlp.maven.plugins
+ liberty-maven-plugin
+ ${openliberty.maven.version}
+
+
+ package-server
+ package
+
+ create-server
+ install-apps
+
+
+ target/wlp-package
+
+
+
+
+
+ io.openliberty
+ openliberty-webProfile8
+ ${openliberty.version}
+ zip
+
+ target/classes/config/server.xml
+ ${project.build.directory}/${project.build.finalName}.war
+ project
+ ${project.basedir}/src/main/liberty/server
+ apps
+ true
+
+
+
+
+
+
+ oauth2-authorization-server
+ oauth2-resource-server
+ oauth2-client
+
+