Azure B2C с OpenID Connect и PKCE

Я пытаюсь войти в Azure B2C с помощью Laravel, сейчас я на полпути.

Часть Laravel — это API, а клиент — в Angular. Я планировал сделать весь процесс на BE. Когда пользователь нажимает «Войти с помощью Microsoft», он перенаправляется на серверную страницу BE, и я делаю волшебство на BE. В итоге хочу сделать редирект на какую-нибудь FE страницу и прописать токен доступа в куке.

Я определил два маршрута web.php (на стороне сервера). Первый предназначен для перенаправления на логин Azure, а второй — для обратного вызова.

Вот код:

public function redirect()
{
    $length = mt_rand(43, 128);
    $bytes = random_bytes($length);
    $codeVerifier = rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');

    $state = Str::random(40);

    $query = http_build_query([
        'p' => 'B2C_1A_SIGNIN',
        'client_id' => config('services.azureadb2c.client_id'),
        'redirect_uri' => config('services.azureadb2c.redirect'),
        'response_type' => 'code',
        'scope' => 'openid',
        'state' => $state,
        'prompt' => 'login',
        'code_challenge' => $this->generateCodeChallenge($codeVerifier),
        'code_challenge_method' => 'S256',
    ]);

    session(['state' => $state, 'code_verifier' => $codeVerifier]);

    return redirect('https://' . config('services.azureadb2c.domain') . '.b2clogin.com/' . config('services.azureadb2c.domain') . '.onmicrosoft.com/b2c_1a_signin/oauth2/v2.0/authorize?' . $query);
}

public function callback(Request $request)
{
    $client = new Client();
    $response = $client->post("https://" . config('services.azureadb2c.domain') . ".b2clogin.com/" . config('services.azureadb2c.domain') . ".onmicrosoft.com/b2c_1a_signin/oauth2/v2.0/token?p=B2C_1A_SIGNIN", [
        'form_params' => [
            'grant_type' => 'authorization_code',
            'client_id' => config('services.azureadb2c.client_id'),
            'client_secret' => config('services.azureadb2c.client_secret'),
            'code' => $request->get('code'),
            'redirect_uri' => config('services.azureadb2c.redirect'),
            'code_verifier' => session('code_verifier'),
            'scope' => 'openid',
        ],
    ]);
    var_dump(json_decode($response->body()));
    exit;
}

private function generateCodeChallenge($codeVerifier) {
    $hash = hash('sha256', $codeVerifier, true);
    $codeChallenge = rtrim(strtr(base64_encode($hash), '+/', '-_'), '=');
    return $codeChallenge;
}

Здесь я столкнулся со следующей проблемой. Перенаправление работает хорошо, пользователь перенаправляется правильно, и он может правильно ввести учетные данные и все такое. В конце обратного вызова я получаю код авторизации, но когда я делаю запрос POST для получения токена доступа, я получаю следующую ошибку

`400 Bad Request` response: {"error":"invalid_grant","error_description":"AADB2C90085: The service has encountered an internal error. Please reauthe (truncated...)

У вас есть идеи, что может вызвать эту ошибку?

Вы видели и пробовали это stackoverflow.com/questions/71139597/…?

Anand Sowmithiran 15.02.2023 14:26

@AnandSowmithiran Я видел этот пример, но он не имеет отношения к моему варианту использования. Этот пример содержит неявный поток, который возвращает токен доступа без кода авторизации. В моем случае я хочу войти в систему с помощью OpenID Connect и PKCE.

5ar5kovic 15.02.2023 14:37

Полученная вами ошибка указывает на то, что предоставленной вами «области действия» недостаточно для возврата токена идентификатора.

Anand Sowmithiran 15.02.2023 15:02

@Ананд спасибо. Что я должен сделать, чтобы попытаться исправить это? Единственная поддерживаемая область — «openid», и я использую ее. Здесь я не получаю токен ID. На первом этапе я получаю только код авторизации, а затем передаю его, чтобы получить токен доступа.

5ar5kovic 15.02.2023 15:17

Попробуйте передать идентификатор клиента также как одно значение области вместе с openid, просто подсказка из Learn.microsoft.com/en-us/azure/active-directory-b2c/…

Anand Sowmithiran 15.02.2023 15:28

не помогло, пробовал разные варианты.

5ar5kovic 15.02.2023 15:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
6
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я попытался воспроизвести то же самое в своей среде через Postman и получил следующие результаты:

Я зарегистрировал одно приложение Azure AD B2C, выбрав SPA в URI перенаправления, как показано ниже:

Я выполнил приведенный ниже код C# от Bac Hoang [MSFT] из этого блога и успешно получил значения code_challenge и code_verifier, как показано ниже:

using IdentityModel;
using System.Security.Cryptography;
using System.Text;
 
namespace PKCEConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var random = new Random();
            int cvlength = random.Next(43, 128);
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
            var codeVerifier = new string (Enumerable.Repeat(chars, cvlength).Select(s => s[random.Next(s.Length)]).ToArray());
 
            string codeChallenge;
            using (var sha256 = SHA256.Create())
            {
                var a = Encoding.UTF8.GetBytes(codeVerifier);
                var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
                codeChallenge = Base64Url.Encode(challengeBytes);
            }
 
            Console.WriteLine("codeVerifier " + codeVerifier + "\n");
            Console.WriteLine("codeChallenge " + codeChallenge + "\n");
 
            Console.ReadLine();
        }
    }
}

Ответ:

Теперь я запустил ниже запрос авторизации в браузере и успешно получил такой код:

https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/authorize?
client_id=742978eb-ccb4-4b82-8140-3526417d4d09
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=openid
&code_challenge=l-kik2UPt2cInWJK6liasiRBhdpNm3qeOqUma_4Ih7E
&code_challenge_method=S256

Ответ:

Когда я попытался сгенерировать токены через Postman с указанными ниже параметрами, я получил только id_token и refresh_token без токена доступа, как показано ниже:

POST https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/token

client_id:742978eb-ccb4-4b82-8140-xxxxxxxxxx
grant_type:authorization_code
scope:openid
code: <paste code from above step>
redirect_uri: https://jwt.ms
code_verifier:hMl0zyCvyUKJxS1gjOPqFNf1LPQ~tcvekFJeWsfzFGSFMi5~QkpCAq1QHMDT3N

Ответ:

Чтобы получить токен доступа, добавьте новую область действия, предоставив API, как показано ниже:

Теперь добавьте этот scope в свое приложение, которое будет иметь делегированные разрешения, как показано ниже:

Обязательно дайте согласие администратора на указанную выше область, как показано ниже:

Теперь снова сгенерируйте code, выполнив приведенный ниже запрос авторизации в браузере следующим образом.

https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/authorize?
client_id=742978eb-ccb4-4b82-8140-xxxxxxxxxx
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=https://sritenantb2c.onmicrosoft.com/742978eb-ccb4-4b82-8140-xxxxxxxxxx/.default
&code_challenge=l-kik2UPt2cInWJK6liasiRBhdpNm3qeOqUma_4Ih7E
&code_challenge_method=S256

Ответ:

Я успешно сгенерировал токен доступа, используя следующие параметры через Postman, как показано ниже:

POST https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/token

client_id:742978eb-ccb4-4b82-8140-xxxxxxxxxx
grant_type:authorization_code
scope: https://sritenantb2c.onmicrosoft.com/742978eb-ccb4-4b82-8140-xxxxxxxxxxx/Admin.Read openid
code: <paste code from above step>
redirect_uri: https://jwt.ms
code_verifier:hMl0zyCvyUKJxS1gjOPqFNf1LPQ~tcvekFJeWsfzFGSFMi5~QkpCAq1QHMDT3N

Ответ:

Когда я расшифровал вышеуказанный токен доступа в jwt.ms, я получил утверждение scp, как показано ниже:

Спасибо! Похоже, проблема была в отправке client_secret в запросе, когда я удалил этот параметр, как в вашем примере, тогда он сработал.

5ar5kovic 16.02.2023 12:57

Другие вопросы по теме

Похожие вопросы