AWS API Gateway – Troubleshooting -blocked by CORS policy

Error: has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Solution: Update your lambda handler function (aws doc)

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "https://www.example.com",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
        },
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

AWS Cognito + MP JWT RBAC + Quarkus

In this blog, we will try to build a Role-Based-Access-Control (RBAC) with Quarkus, MicroProile JWT RBAC and AWS Cognito.

AWS Cognito will create JWT token and RSA Public Key Distribution. Quarkus, MicroProile are responsible for Java Server-side API endpoints.

Useful links:

Eclipse MicroProfile – JWT RBAC Security (MP-JWT)

QUARKUS – USING JWT RBAC

  • Create AWS Cognito User Pool and then in this User Pool create a User and Group. Here we use “Cognito Groups” as “User Roles”.
  • Create an AWS Cognito Identity Pool and get an identity pool Id , eg "eu-central-1_xxxxx". This Cognito Identity Pool will be the JWT Issuer and we could find the RSA Publicy Key under "https://cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxxx/.well-known/jwks.json"
  • Create the endpoint by using Quarkus, for example:
@Path("/orders")
@RequestScoped
public class OrderResource {

    @GET
    @RolesAllowed({"USER", "ADMIN"})
    @Produces(MediaType.APPLICATION_JSON)
    public Response list(){
        return Response.ok(Arrays.asList("Order1", "Order2")).build();
    }
}

Most important since the default group claim in MP-JWT is “groups” but the Cognito group claim is “cognito:groups” so we need config a mapping.

smallrye.jwt.path.groups=cognito:groups

Other necessary configs:

mp.jwt.verify.publickey.location=https://cognito-idp.eu-central-1.amazonaws.com/eu-central-xxxxx.well-known/jwks.json

mp.jwt.verify.issuer=https://cognito-idp.eu-central-1.amazonaws.com/eu-central-xxxxx

quarkus.smallrye-jwt.enabled=true
quarkus.smallrye-jwt.auth-mechanism=MP-JWT
quarkus.smallrye-jwt.realm-name=Quarkus-JWT

For testing and getting a cognito jwt token you could try aws cli:

aws cognito-idp admin-initiate-auth --region eu-central-1 --cli-input-json file://auth.json

Then you put that token in the HTTP header “Authorization” and begins with “Bearer ” for example:

curl -X GET \
https://example/orders \
-H 'Authorization: Bearer YOUR_JWT_TOKEN' \

There you are the integration Quarkus + MP JWT and AWS Cognito. Enjoy!

This blog is under category “API“.

REST API Part2

  • Stateless:  RESTFul API is stateless. A stateless protocol does not require the server to retain session information or status about each communicating partner for the duration of multiple requests.

UDP, HTTP, and IP are stateless protocols. TCP is stateful.

  • HEAD, GET, OPTIONS and TRACE are SAFE methods,which means they are intended only for information retrieval and should not change the state of the server. In other words, they should not have side effects.
  • Methods PUT and DELETE are defined to be idempotent, meaning that multiple identical requests should have the same effect as a single request. Methods GET, HEAD, OPTIONS, and TRACE, being prescribed as safe, should also be idempotent.

Build Reactive Restful API Using Spring 5 (WebFlux), Springboot

1. Spring 5 WebFlux

Spring 5 includes a new reactive module called WebFlux. It builds on the reactive streams. (Key Spring Doc)

WebFlux support two programming models: one is traditional based@controller, the other is functional Java 8 lambda style routing and handling.  Here we will take a look at the second one.

In general, the second WebFlux model takes incoming http request, handed by the HandlerFunction , then http request body transforms to as Flux or Mono;

Flux and Mono come from the reactor (doc). A Flux object represents a reactive sequence of 0..N items, while a Monoobject represents a single-value-or-empty (0..1) result.

2. Code example
2.1 Create a handler:

@Component
public class UserHandler {

    public Mono getUser(ServerRequest request){
            try{
                String uuid = request.pathVariable("uuid");
                return ServerResponse
                        .ok()
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromObject(new UserJson(uuid, "bob")));
            }catch (IllegalArgumentException i){
                return ServerResponse.badRequest()
                        .contentType(MediaType.TEXT_PLAIN)
                        .body(BodyInserters.fromObject(i.getMessage()));
            }
    }
}
2.2 Create a route:

@Configuration
public class UserRouter {

    @Bean
    public RouterFunction route(UserHandler userHandler){
        return RouterFunctions.route(RequestPredicates.GET("/users/{uuid}").
                and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                userHandler::getUser);
    }
}

Source Code example Github

Building Restful API using Springboot

1.Create Spring-boot project

IntelliJ IDEA CE doesn’t support “spring initializr” plugin, so we should initial a SpringBoot project using https://start.spring.io/

Download and unzip project, import it into IntelliJ.

2. Coding
  • Using  @RestController annotation which equals :  @controller + @ResponseBody
  •  Springboot main class should be in the same package with controllers and it should be in the root.

  • Code Controller:

@RestController
public class UserController {

    @RequestMapping(value = "/users/{uuid}", method = RequestMethod.GET)
    public ResponseEntity getUser(@PathVariable("uuid") String uuid) {
        UserJson userJson = new UserJson(uuid, "bob");
        return new ResponseEntity<>(userJson, HttpStatus.OK);
    }
}
  • Code Entity:

public class UserJson {

    @JsonProperty(value = "uuid")
    private String uuid;

    @JsonProperty(value = "name")
    private String name;

    public UserJson(String uuid, String name) {
        this.uuid = uuid;
        this.name = name;
    }
}
  • Run project

Configration Context and Port (Modifiy application.properties)


./gradlew build bootRun

Source Code Github

play framework (filter, action)

1. KeY concepts of http architect in Play framework

In core play2, the handling of HTTP is :


RequestHeader -> Array[Byte] -> Result 
RequestHeader -> Iteratee[Array[Byte],Result]

The above computation takes the request header RequestHeader, then takes the request body as Array[Byte] and produces a Result. (play doc)

2. action and filter

Most of the requests received by a Play application are handled by an Action.

A play.api.mvc.Action is basically a (play.api.mvc.Request => play.api.mvc.Result) function that handles a request and generates a result to be sent to the client.

A Controller is nothing more than a singleton object that generates Action values. (play doc)

The Filter is applying global filters to each request.

3. Using Filter and action

The filter is used for all the routes. Action can be customized for certain route (on a specific controller)

Using Filter for creating global ratelimter for the API:


public class GlobalRatelimitFilter extends Filter {

    private static final long MAX_REQUESTS = 10;
    private static final long PERIOD = 60;
    private AtomicLong remainingRequests;
    private Instant expirationTime;

    @Inject
    public GlobalRatelimitFilter(Materializer mat) {
        super(mat);
        this.remainingRequests = new AtomicLong(MAX_REQUESTS);
        this.expirationTime = Instant.now().plusSeconds(PERIOD);
    }

    @Override
    public CompletionStage apply(Function<Http.RequestHeader, CompletionStage> next, Http.RequestHeader rh) {

        if (Instant.now().isAfter(this.expirationTime)) {
            this.remainingRequests = new AtomicLong(MAX_REQUESTS);
            this.expirationTime = Instant.now().plusSeconds(PERIOD);
        }
        if (this.remainingRequests.get() > 0L) {
            this.remainingRequests.getAndDecrement();
            return next.apply(rh).thenApply(result -> result.withHeader("X-Remaining-Ratelimit", String.valueOf(this.remainingRequests.get())));
        } else {
            return CompletableFuture.completedFuture(Results.status(429, "too many requests globally"));
        }
    }
}

code github

Using action for creating specific ratelimiter for certain routes:


public class RatelimitAction extends Action {

    private static final String USER_ENDPOINT_RATELIMIT = "user-endpoint-ratelimit";

    @Inject
    @NamedCache("ratelimit-cache")
    private SyncCacheApi cache;

    @Override
    public CompletionStage call(Http.Context ctx) {
        int limit = configuration.limit();
        int period = configuration.period();
        Ratelimit ratelimit = cache.getOrElseUpdate(USER_ENDPOINT_RATELIMIT, () -> new Ratelimit(limit, period));

        if (ratelimit.expired()) {
            ratelimit = new Ratelimit(limit, period);
            cache.set(USER_ENDPOINT_RATELIMIT, ratelimit);
        }
        ratelimit.decrease();

        if (ratelimit.reached()) {
            return CompletableFuture.completedFuture(Results.status(429, "too may requests for /users endpoint"));
        }

        return delegate.call(ctx);
    }
}

Using Action to control the API, Security, verify the requests before it calling the controller.


public class IPStrictAction extends Action {

    @Override
    public CompletionStage call(Http.Context ctx) {

        String[] whiteListIPs = configuration.whiteListIPs();

        String clientHost = ctx.request().host().split(":")[0];

        if(!iPwhitelisted(whiteListIPs, clientHost)){
            CompletableFuture.completedFuture(Results.status(403, "IP not allowed"));
        }

        return delegate.call(ctx);
    }

    private boolean iPwhitelisted(String[] whiteListIPs, String clientHost) {
        return Arrays.asList(whiteListIPs).contains(clientHost);
    }
}

Code Github

RESTful API is all about resource

The heart of the design of restful API is around `resource`.

GET, POST, PUT, DELETE, etc – HTTP verbs to manipulate resources.

URL –  the path to locating the resources.

Some options for restful API design:

Endpoints (URL):
  • using plural nouns, lowercase.(e.g.  prod.api.aerodc/users/:id/settings)
  • always putting ‘: id’ in the path, not in the body Json.
HTTP Response code:
  • not found for findAll -> 200 with empty resources
  • not found for findById -> 404 not found
  • 201: post resource created
  • 204:  no content. deleted resource
  • 202:  HTTP PUT or in some microservice environment
  • 400: Bad request (wrong format parameters)
  • 401: Unauthorized (missing parameters)
  • 403: Forbidden (security concern)
  • 404: Not found (resources not exist)
  • 409: Conflict (resources already exist)
  • 429: Ratelimit (too many requests)
JSON
  • Property: snake_case
  • For boolean property: avoid using like “is_deleted” is_xxx.
Some good articles about restful api design:

Octohttps://blog.octo.com/en/design-a-rest-api/

Paypalhttps://github.com/paypal/api-standards/blob/master/api-style-guide.md

Gocardlesshttps://github.com/gocardless/http-api-design