authorization – Is a consent screen in an OAuth 2.0 implementation optional

I’ve read through RFC 6749: https://datatracker.ietf.org/doc/html/rfc6749

The only mention of consent is in this bit:

The authorization server MUST implement CSRF protection for its
authorization endpoint and ensure that a malicious client cannot
obtain authorization without the awareness and explicit consent of
the resource owner.

The above does not (to me anyway) translate to: “Hey show a consent screen with requested scopes before responding with an authorisation”.

I’ve seen so many OAuth 2.0 implementations however where a consent screen is shown.

Question 1: As per the title really – is it actually needed?

Question 2: Is there an RFC that specifies what such a consent screen (if you are to implement one) should look like, including any required messaging and response if the user declines?

Should biometric authentication grant authorization to the previously logged in user in an Android app?

I want my users to be able to use biometrics for easier access, but I’m not sure if it’s a standard practice (having in mind the security of it). I’m thinking of a situation where user A logged in on user’s B device and later user B would use biometrics on xir own device to gain access to user A’s, previously logged in, account.

I have no idea if it’s common practice to ignore that situation or not.

javascript – Function to build authorization header for an OAuth1 request

I have a function that builds the Authorization header for an OAuth1 request. It works as expected but I think it can be heavily improved, although not sure what would be the best approach to tidy this up.

I want to clean the oAuthV1Request function as it feels very messy and using a lot of duplicate code:

import qs from "querystring";
import authorization from "./authorization/authorization";
import { percentEncode } from "./authorization/helpers";
import { AuthorizationOptions } from "./types";

function buildBody(
  bodyParams: Record<string, string | number | boolean>
): string {
  return qs.stringify(bodyParams, "&", "=", {
    encodeURIComponent: percentEncode,
  });
}

export default function oAuthV1Request(options: AuthorizationOptions): {
  method: "GET" | "PUT" | "POST" | "DELETE";
  baseURL: string;
  params: Record<string, string>;
  data: string;
  headers: {
    Authorization: string;
    "Content-Type": "application/x-www-form-urlencoded";
    "Content-Length": number;
  };
};
export default function oAuthV1Request(
  options: Omit<AuthorizationOptions, "data">
): {
  method: "GET" | "PUT" | "POST" | "DELETE";
  baseURL: string;
  params: Record<string, string>;
  headers: {
    Authorization: string;
  };
};
export default function oAuthV1Request(
  options: Omit<AuthorizationOptions, "params">
): {
  method: "GET" | "PUT" | "POST" | "DELETE";
  baseURL: string;
  data: string;
  headers: {
    Authorization: string;
    "Content-Type": "application/x-www-form-urlencoded";
    "Content-Length": number;
  };
};
export default function oAuthV1Request(
  options: Omit<AuthorizationOptions, "params" | "data">
): {
  method: "GET" | "PUT" | "POST" | "DELETE";
  baseURL: string;
  headers: {
    Authorization: string;
  };
};
export default function oAuthV1Request(options: AuthorizationOptions):
  | {
      method: "GET" | "PUT" | "POST" | "DELETE";
      baseURL: string;
      params: Record<string, string>;
      headers: {
        Authorization: string;
      };
    }
  | {
      method: "GET" | "PUT" | "POST" | "DELETE";
      baseURL: string;
      data: string;
      headers: {
        Authorization: string;
        "Content-Type": "application/x-www-form-urlencoded";
        "Content-Length": number;
      };
    }
  | {
      method: "GET" | "PUT" | "POST" | "DELETE";
      baseURL: string;
      headers: {
        Authorization: string;
      };
    }
  | {
      method: "GET" | "PUT" | "POST" | "DELETE";
      baseURL: string;
      params: Record<string, string>;
      data: string;
      headers: {
        Authorization: string;
        "Content-Type": "application/x-www-form-urlencoded";
        "Content-Length": number;
      };
    } {
  if (options.params && options.data) {
    const data = buildBody(options.data || {});
    return {
      baseURL: options.baseURL,
      method: options.method,
      params: options.params,
      data,
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "Content-Length": Buffer.byteLength(data),
        Authorization: authorization(options),
      },
    };
  }

  if (options.data) {
    const data = buildBody(options.data || {});
    return {
      baseURL: options.baseURL,
      method: options.method,
      data,
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "Content-Length": Buffer.byteLength(data),
        Authorization: authorization(options),
      },
    };
  }

  if (options.params) {
    return {
      baseURL: options.baseURL,
      method: options.method,
      params: options.params,
      headers: {
        Authorization: authorization(options),
      },
    };
  }

  return {
    baseURL: options.baseURL,
    method: options.method,
    headers: {
      Authorization: authorization(options),
    },
  };
}

Also, any feedback in general regarding any kind of improvement or code smell would be great.

Repo with all the code in case more context is useful.

What is causing error “403 FORBIDDEN (Access not allowed even with authorization)” for new domain on Domino server?

With Domino 9 server, a new Virtual Hostname doc has been added to the Domino Directory for domain xxxxx.app. It is configured with default values, and there are several other web sites hosted on the server with the same configuration. SSL is running on one of the domains, but all the rest are HTTP.

However, the site is not accessible via the browser giving the error message:

403 FORBIDDEN (Access not allowed even with authorization)

The only difference between this site and the others is that it has an .app high level domain name, and it was added to the Directory after the SSL key had been installed for a different domain name.

What may be causing forbidden access even with authorization?

domain driven design – Authorization and Cross-Cutting Concerns in DDD (CQRS) – Filtering Data

We are currently in the early phases of developing several applications that differ significantly in their functionality. As part of building these applications, we have also developed a few generic BCs. Ideally these BCs should be reusable in order to minimize duplication and remove cross cutting conerns, and further improve development of future applications. Among these are a generic BC used to handle notifications such as emails, a BC dedicated to activity feeds, and more–and even more in the future.

This all works well and nicely in terms of the functionality they implement. However, I am unsure as to how to handle authorization and filtering of data in the case of either querying or executing commands.

Essentially, the source of truth with respect to the authorization rules are the non-generic applications/BCs. These applications can be totally different, but they all require authorization and the use of zero or more of the aforementioned generic BCs. Now, comes the question: What is the best way to handle this cross cutting concern without having to duplicate authorization logic for each new application we develop?

Our plan was originally to have a generic BC for Security that stores information about the resources and subjects that are in the system. In order to enforce the authorization, we envisioned developing an API-gateway for each non-generic application we develop and have the API-gateway enforce security policies. This approach should work well for handling authorization of command.

However, for queries, things seem to be complicated. For instance, our activity feeds may contain records that only a subset of the users of some application should be able to see, based on their roles in that specific application. In addition, some users may be able to only access a subset of the information of the returned records. For instance when fetching information from the generic BC that handles a Filesystem, some documents should be visible to some, while hidden from others.

Would filtering the information provided by the generic BC in the API-gateway before returning the data be a viable solutions? For instance when a given user fetches an activity feed from the Activity BC, the API-gateway queries the Security BC for information required to filter the results. This would incur overhead by having unnecessary data returned from the generic BC (i.e. the records/fields that are removed after filtering), but on the other hand this greatly reduces the complexity that filtering within that BC itself would incur. To me it seems that there should be a better approach without polluting each and every generic BC with authorization logic.

I have also read about the sidecar pattern. Would it make sense that each service implementing a generic BC has a sidecar containing the generic Security/Authorization BC? In order to avoid polluting each QueryHandler with authorisation filtering, the query result could e.g. be passed through a filter that interacts with the sidecar.

I am sorry for the long post; I hope I articulated myself in an understandable way. The approach to solving cross cutting concerns in DDD (and microservices) seem to be a highly debated topic, and it can be overwhelming to interpret the massive amounts of opinions regarding this.

Alter authorization on all non-system SQL Server databases

I am not very experienced with T-SQL and feel this can be done better. The script changes ownership of all “user” (non-system) databases to sa.

Usage of a dynamic SQL expression seems unavoidable to me. Could I at least iterate the table names in a more elegant way — imperative code looks like a code smell in a SQL script. Nested query in the while loop absolutely hurts my eyes…

How to rewrite this script to be more idiomatic?

DROP TABLE IF EXISTS #databaseNames;

SELECT name
INTO #databaseNames
FROM master.sys.databases
WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb')

DECLARE @tableCount integer
SELECT @tableCount = COUNT(*) FROM #databaseNames

DECLARE @tableNumber integer
SET @tableNumber = 1

WHILE @tableNumber <= @tableCount
BEGIN

  DECLARE @tableName varchar(1024)
  
  SELECT @tableName = name FROM (
    SELECT
      ROW_NUMBER() OVER (ORDER BY name ASC) AS rowNumber,
      name
    FROM #databaseNames
  ) numberedDatabaseNames
  WHERE rowNumber = @tableNumber

  EXEC('alter authorization on database::' + @tableName + ' to sa;')

  SET @tableNumber = @tableNumber + 1
END;

magento2.4.1 – How to achieve set Google Business Reviews Authorization Bearer Token?

I am using Google Business Review API, every time i manually copy and paste the Bearer token, how to achieve this?,

My code :

<?php
namespace ZeroStorelocatorBlock;

class Customerreview extends MagentoFrameworkViewElementTemplate
{
public function __construct(
AmastyStorelocatorBlockviewAttributes $attributes,
MagentoFrameworkViewElementTemplateContext $context,
MagentoFrameworkAppConfigScopeConfigInterface $scopeConfig,
array $data = ()
) {
$this->_attributes = $attributes;
$this->scopeConfig = $scopeConfig;
parent::__construct($context, $data);
}

protected function _prepareLayout()
{
parent::_prepareLayout();

}

public function getCustomerReview(){

//Here you need to check system.xml file and get section_id/group_id/field_id
$authentication = $this->scopeConfig->getValue('customerreview/general/review_auth', MagentoStoreModelScopeInterface::SCOPE_STORE);

$accountId = $this->scopeConfig->getValue('customerreview/general/review_account_id', MagentoStoreModelScopeInterface::SCOPE_STORE);

$authorization = "Authorization:".$authentication;
$url = 'https://mybusiness.googleapis.com/v4/accounts/'.$accountId.'/locations/45545454545454545454545/reviews';

$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization ));
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$output = curl_exec($ch);

$writer = new ZendLogWriterStream(BP . '/var/log/output.log');
$logger = new ZendLogLogger();
$logger->addWriter($writer);
$logger->info(print_r('line no:42'. $output, true));

$allData = json_decode($output, TRUE); // You will get all the data

return $allData;

}

public function getCustomAttributes()
{
if ($this->_attributes->getLocationAttributes()) {
return '';
}
return $this->_attributes->getLocationAttributes();
}
}

magento2.4.1 – How to generate Google Business Reviews Authorization Bearer Token auto refresh

I am using Google Business Review API, every time i manually copy and paste the token, how to refresh automatically,

My code :

<?php
namespace ZeroStorelocatorBlock;

class Customerreview extends MagentoFrameworkViewElementTemplate
{
public function __construct(
AmastyStorelocatorBlockviewAttributes $attributes,
MagentoFrameworkViewElementTemplateContext $context,
MagentoFrameworkAppConfigScopeConfigInterface $scopeConfig,
array $data = ()
) {
$this->_attributes = $attributes;
$this->scopeConfig = $scopeConfig;
parent::__construct($context, $data);
}

protected function _prepareLayout()
{
parent::_prepareLayout();

}

public function getCustomerReview(){

//Here you need to check system.xml file and get section_id/group_id/field_id
$authentication = $this->scopeConfig->getValue('customerreview/general/review_auth', MagentoStoreModelScopeInterface::SCOPE_STORE);

$accountId = $this->scopeConfig->getValue('customerreview/general/review_account_id', MagentoStoreModelScopeInterface::SCOPE_STORE);

$authorization = "Authorization:".$authentication;
$url = 'https://mybusiness.googleapis.com/v4/accounts/'.$accountId.'/locations/45545454545454545454545/reviews';

$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization ));
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$output = curl_exec($ch);

$writer = new ZendLogWriterStream(BP . '/var/log/output.log');
$logger = new ZendLogLogger();
$logger->addWriter($writer);
$logger->info(print_r('line no:42'. $output, true));

$allData = json_decode($output, TRUE); // You will get all the data

return $allData;

}

public function getCustomAttributes()
{
if ($this->_attributes->getLocationAttributes()) {
return '';
}
return $this->_attributes->getLocationAttributes();
}
}