diff --git a/nginx/auth.js b/nginx/auth.js
index d91b591388a96b999faa9b82aa2b1e0be9b5aac4..905db872e655199d2be2a45411c66a56335e2424 100644
--- a/nginx/auth.js
+++ b/nginx/auth.js
@@ -1,86 +1,146 @@
-async function authenticate_and_authorize(r) {
-  try {
-    const required_params = {
-      path: r.variables["request_uri"],
-      method: r.variables["request_method"],
-      server_name: r.variables["ssl_server_name"],
+const InvalidJSONError = JSON.stringify({
+  status: 400,
+  title: "Invalid JSON",
+});
+
+function check_body_size(r) {
+  // Check if the body has been buffered to a temp file.
+  // If this is the case, warn the admin to configure the client_body_buffer_size
+  // to be equal to client_max_body_size
+  // https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size
+  if (r.variables["request_body_file"]) {
+    // maybe return 500
+    return {
+      error:
+        "Request Entity Too Large. Please set 'client_body_buffer_size' to be equal to 'client_max_body_size' in the NGINX configuration file.",
+      status: 413,
+      message: "Request Entity Too Large",
     };
+  } else {
+    return {};
+  }
+}
 
-    let opa_input = required_params;
-    if(r.requestBuffer){
-      opa_input = Object.assign(
-        JSON.parse(r.requestBuffer),
-        required_params
-      );
-    }
+async function token_is_valid(r, token) {
+  const response = await r.subrequest("/_opa/v1/data/authn", {
+    method: "POST",
+    body: JSON.stringify({ input: { access_token: token } }),
+  });
+  const body = JSON.parse(response.responseText);
+  return body.result.jwt_is_valid;
+}
 
-    const authz_header = r.headersIn["Authorization"];
-
-    let is_bearer_authn = false;
-    if (authz_header && authz_header.startsWith("Bearer")) {
-      const jwt = authz_header.substring(7);
-      opa_input["access_token"] = jwt;
-      is_bearer_authn = true;
-    } else if (r.variables["voms_fqans"]) {
-      opa_input["voms_fqan"] = r.variables["voms_fqans"].split(",");
-    } else if (r.variables["ssl_client_s_dn"]) {
-      opa_input["ssl_client_s_dn"] = r.variables["ssl_client_s_dn"];
+async function process_authn(r) {
+  const authz_header = r.headersIn["Authorization"];
+  if (authz_header && authz_header.startsWith("Bearer")) {
+    const jwt = authz_header.substring(7);
+    const valid = await token_is_valid(r, jwt);
+    if (valid) {
+      return { access_token: jwt };
     } else {
-      r.return(401, "no usable credentials presented");
-      return;
+      return { error: "Invalid access token", status: 401 };
     }
+  } else if (r.variables["voms_fqans"]) {
+    return { voms_fqan: r.variables["voms_fqans"].split(",") };
+  } else if (r.variables["ssl_client_s_dn"]) {
+    return { ssl_client_s_dn: r.variables["ssl_client_s_dn"] };
+  }
+  return { error: "No usable credentials presented", status: 401 };
+}
 
-    const opts = {
-      method: "POST",
-      body: JSON.stringify({ input: opa_input }),
-    };
+function is_body_valid(body) {
+  const paths_are_valid = () => {
+    const paths = body.paths;
+    if (!paths || !paths instanceof Array) {
+      return false;
+    }
+    return paths.every((path) => typeof path === "string");
+  };
 
-    if(is_bearer_authn){
-      const opa_res = await r.subrequest("/_opa/v1/data/authn", opts);
-      r.log(`OPA Auth responded with status ${opa_res.status}`);
-      const body = JSON.parse(opa_res.responseText);
-
-      const request_method = r.variables["request_method"]
-      switch(request_method){
-        case "GET":
-        case "DELETE":
-        case "HEAD":
-          if(!body.result.jwt_is_valid){
-            r.return(401);
-            return;
-          }
-          break;
-        default:
-          if(!body.result.jwt_is_valid_and_trusted){
-            r.return(401);
-            return;
-          }
-      }
+  const files_are_valid = () => {
+    const files = body.files;
+    if (!files || !files instanceof Array) {
+      return false;
     }
+    return files.every((file) => typeof file.path === "string");
+  };
 
-    const opa_res = await r.subrequest("/_opa/v1/data/rules/allowed", opts);
-    r.log(`OPA Rules responded with status ${opa_res.status}`);
-    const body = JSON.parse(opa_res.responseText);
-    if (!body.result) {
-      r.return(403);
+  return paths_are_valid(body) || files_are_valid(body);
+}
+
+async function process_authz(r, authn_response, request_body) {
+  const opa_input = {
+    path: r.variables["request_uri"],
+    method: r.variables["request_method"],
+  };
+  Object.assign(opa_input, authn_response, request_body);
+
+  const opa_res = await r.subrequest("/_opa/v1/data/rules", {
+    method: "POST",
+    body: JSON.stringify({ input: opa_input }),
+  });
+
+  r.log(`OPA AuthZ responded with status ${opa_res.status}`);
+
+  const body = JSON.parse(opa_res.responseText);
+  if (body && body.result.allowed) {
+    return { status: 200 };
+  }
+
+  return { error: "Forbidden", status: 403 };
+}
+
+async function process_storm(r) {
+  const url = "/_storm-tape" + r.variables["request_uri"].replace(/\/$/, "");
+  const method = r.variables["request_method"];
+  const res = await r.subrequest(url, { method });
+  r.log(`StoRM Tape responded with status ${res.status}`);
+  return res;
+}
+
+async function process(r) {
+  try {
+    const resp = check_body_size(r);
+    if (resp.error) {
+      r.log(resp.error);
+      r.return(resp.status, resp.message);
+    }
+    // AuthN
+    const authn = await process_authn(r);
+    if (authn.error) {
+      r.log(authn.error);
+      r.return(authn.status);
       return;
     }
 
-    const storm_res = await r.subrequest(
-      "/_storm-tape" + r.variables["request_uri"].replace(/\/$/, ""),
-      {
-        method: r.variables["request_method"],
-        body: r.requestBuffer,
-      }
-    );
+    // Validate body
+    const request_body = r.requestText ? JSON.parse(r.requestText) : null;
+    if (request_body && !is_body_valid(request_body)) {
+      r.headersOut["Content-Type"] = "application/json+problem";
+      r.log("Invalid JSON");
+      r.return(400, InvalidJSONError);
+      return;
+    }
+
+    // AuthZ
+    const authz = await process_authz(r, authn, request_body);
+    if (authz.error) {
+      r.log(authz.error);
+      r.return(403);
+      return;
+    }
 
-    r.log(`StoRM Tape Responded with status ${storm_res.status}`);
+    // Sent request to StoRM Tape
+    const storm_res = await process_storm(r);
     r.headersOut["Location"] = storm_res.headersOut["Location"];
-    r.return(storm_res.status, storm_res.responseText);
+    if (storm_res.status) {
+      r.return(storm_res.status, storm_res.responseText);
+      return;
+    }
   } catch (err) {
     r.log(err);
-    r.return(500);
+    r.return(403); // or 500?
   }
 }
 
-export default { authenticate_and_authorize };
+export default { process };
diff --git a/nginx/storm.conf b/nginx/storm.conf
index 2716e3c2ab19d8213cb3f8491c64199826f1f874..7051f694c3fa49425c5b2e62dd32e29cbe16806f 100644
--- a/nginx/storm.conf
+++ b/nginx/storm.conf
@@ -18,6 +18,7 @@ server {
   ssl_verify_depth 100;
 
   client_max_body_size 0;
+  client_body_buffer_size 1m;
 
   location /api/v1 {
 
@@ -39,7 +40,8 @@ server {
     proxy_set_header        X-Request-Id $request_id;
 
     proxy_pass_request_body on;
-    js_content auth.authenticate_and_authorize;
+    js_content              auth.process;
+   
   }
 
   location /_storm-tape/ {