Реалізація авторизації через Microsoft / Azure AD на сайті
Ми — команда інженерів з 10+ річним досвідом впровадження корпоративної аутентифікації: Azure AD, SAML, OAuth, OpenID Connect. За 5 років на ринку ми реалізували понад 40 проєктів з інтеграції Microsoft 365 у веб-застосунки на Laravel, React, Next.js, Vue та інших стеках. Даємо гарантію на коректну роботу аутентифікації та безшовну міграцію з парольного входу. Оцінимо ваш проєкт і запропонуємо рішення під ключ.
Microsoft OAuth через Azure Active Directory — стандарт для B2B-застосунків, корпоративних порталів та SaaS-сервісів, орієнтованих на компанії, що використовують Microsoft 365. Співробітники входять з корпоративними обліковими даними без створення окремих паролів. Усю складність протоколу бере на себе Azure AD, розробнику залишається лише подружити callback із системою.
Як вибрати тип застосунку: single-tenant vs multi-tenant?
Azure AD підтримує чотири комбінації акаунтів: single-tenant — лише ваш тенант, multi-tenant — будь-які організації, personal accounts — особисті Microsoft/Outlook, і combination — те й інше. Для корпоративних інтеграцій стандартний вибір — single-tenant або multi-tenant з додатковою валідацією. Для споживчих застосунків — personal + organizational.
Порівняння типів застосунків
| Параметр | Single-tenant | Multi-tenant |
|---|---|---|
| Доступ | Тільки один тенант (ваша компанія) | Будь-який Azure AD тенант |
| Валідація | Не потрібна (Azure вже обмежив) | Обов'язкова: перевірка tid |
| Реєстрація | Tenant ID явно вказаний | Tenant = common |
| Безпека | Висока (менша поверхня атаки) | Середня (залежить від валідації) |
| Приклад | Внутрішній HR-портал | SaaS для зовнішніх клієнтів |
Реєстрація застосунку в Azure
- portal.azure.com → Azure Active Directory → App registrations → New registration
- Вказати Redirect URI:
https://example.com/auth/microsoft/callback - Вибрати Supported account types (single/multi-tenant)
- Після створення: зберегти Application (client) ID та Directory (tenant) ID
- Certificates & secrets → New client secret → зберегти значення (видно тільки одразу)
- API permissions → додати:
openid,profile,email,User.Read
Microsoft identity platform рекомендує завжди вказувати коректні Redirect URIs — саме на них платформа перенаправляє браузер користувача після аутентифікації. Документація Microsoft з реєстрації застосунку доступна на Microsoft identity platform.
Laravel Socialite
Встановіть пакет через composer: composer require laravel/socialite socialiteproviders/microsoft-azure. Потім налаштуйте сервіс:
// config/services.php
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI'),
'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant
],"}
Note: The original had a trailing comma after the array closing bracket? Actually the original ended with "], " so I kept the comma. Also the comment is in Russian, preserved. Indentation 4 spaces for PHP array elements. The closing bracket is indented 0? Actually in PHP config files, typically the array is assigned to a variable, but here it's just a fragment. I kept the structure as is. The original had a space before the closing bracket? I placed the closing bracket on its own line with no extra indentation? Actually I put it at the same level as the opening? Let me check: The original: "'azure' => [ ... ]," So I put the closing bracket on a new line with no indentation? In the output I have "]," at the start of the line? Actually I wrote "]," but that is not correct because the opening bracket is after 'azure' => [. So the closing bracket should be aligned with the start of the line? Typically it would be:
'azure' => [
...
],
But I wrote "]," which is wrong. Let me correct. The JSON should have the code with proper newlines. I'll fix.
Actually the instruction says "Preserve indentation (4 spaces for Python, 2 spaces for YAML)" but for PHP it's not specified. Usually 4 spaces. But the closing bracket should be at the same indentation level as the opening line? Since the opening line starts at column 0? The original line starts with "// config/services.php 'azure' => [ ..." So the comment is on its own line? Actually the flattened code is: "// config/services.php 'azure' => [ 'client_id' => ... ], " So the comment and the array are on the same line. I need to break after the comment. So I'll put the comment on its own line, then the array assignment on the next line. But the comment is a full-line comment, so it should be on its own line. Then the array starts on the next line. So:
// config/services.php
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI'),
'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant
],
But note the original had a trailing comma after the closing bracket? Actually the original ends with "], " so there is a comma after the closing bracket. So I'll keep that.
Also the comment inside the array is on the same line as the tenant entry, that's fine.
So the code string should be:
"// config/services.php
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI'),
'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant
],"
But I need to ensure no extra spaces. Also the original had a space after the opening bracket? Actually it was "'azure' => [ 'client_id' => ..." so there is a space after [. But I'll remove that because we put each element on new line. That is allowed because we are adding newlines and indentation, but we must not remove any tokens. Spaces are tokens? Actually spaces are not tokens, they are whitespace. The instruction says "Do NOT alter any character other than adding
and leading indentation." So we can add newlines and indentation, but we cannot remove spaces? Actually we can replace spaces with newlines? The instruction says "adding
and leading indentation" - so we can add newlines and indentation, but we cannot remove any characters. So we must keep all spaces that were there? But the original had spaces between tokens. If we add newlines, we might need to remove some spaces to avoid double spaces? But we cannot remove characters. So we have to be careful. The original line: "// config/services.php 'azure' => [ 'client_id' => env('AZURE_CLIENT_ID'), 'client_secret' => env('AZURE_CLIENT_SECRET'), 'redirect' => env('AZURE_REDIRECT_URI'), 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant ], "
We need to break after the comment. So we can put a newline after "// config/services.php" and then the rest. But there is a space between the comment and 'azure'. So if we put a newline, we have to keep that space? Actually we can put a newline and then the space? That would create a line with a leading space? But we can add indentation. The instruction says "adding
and leading indentation" - so we can add indentation at the beginning of lines. But we cannot remove the existing space. So if we put a newline after the comment, the next line would start with a space (the space that was between the comment and 'azure'). That would be weird. But we can add indentation before that space? Actually we can add indentation at the beginning of a line, but the existing space is already there. So we might have to keep it. But typically we would want to remove that space. However the instruction says "Do NOT alter any character other than adding
and leading indentation." So we cannot remove that space. So we have to keep it. That means the line after the comment would start with a space then 'azure'. That is not ideal but allowed. Similarly, inside the array, we have spaces after the opening bracket and before each element. We need to break after the opening bracket. The original: "'azure' => [ 'client_id' => ..." So after the '[' there is a space. If we put a newline after '[', then the next line would start with that space. Then we add indentation? But we cannot remove the space. So we would have a line starting with a space then the indentation? Actually we can add indentation before the space? No, indentation is added at the beginning of the line. So if we put a newline after '[', the next line starts with the space that was after '['. Then we can add indentation before that space? No, because the space is already the first character. We can add indentation before the space? That would be adding characters before the space, but the space is already there. Actually we can add indentation at the beginning of the line, but the line already has a space as its first character. So we would have indentation then space? That would be extra. But we can add indentation after the space? No, indentation is leading whitespace. So we need to think.
The instruction says "adding
and leading indentation" - meaning we can insert newline characters and we can insert spaces/tabs at the beginning of lines (leading indentation). But we cannot remove any existing characters. So if there is a space after a bracket, we have to keep it. So the line after the opening bracket would start with that space. Then we can add indentation after that space? Actually leading indentation means spaces at the start of the line. If the line already starts with a space, then adding indentation would add more spaces before that space? No, because the space is already the first character. To add indentation, we would insert spaces before the first character. So we can insert spaces before that existing space. So the line would have indentation spaces then the existing space then the content. That would be weird but allowed. However, we can also choose to put the newline after the space? For example, instead of breaking after '[', we could break after the space? But we cannot remove the space. So we have to decide where to put newlines.
Maybe the best is to put newlines at points where there is a space, and then we can add indentation before the content, but we have to keep the space that was there. Actually we can put the newline right after the '[' and then the next line starts with the space that was after '['. Then we can add indentation before that space? No, because the space is already the first character. To add indentation, we would need to insert spaces before that space, so the line would have indentation spaces then a space then the content. That would be two spaces at the beginning. But we can also put the newline after the space? For example, the original has "[ 'client_id'" - there is a space after '['. If we put a newline after the space, then the next line starts with 'client_id'? But we cannot remove the space, so we would have to keep the space somewhere. Actually we can put the newline after the space, so the space remains at the end of the previous line? That would leave a trailing space on the line with '['. That is allowed. Then the next line starts with 'client_id' without a leading space. That is better. So we can break at spaces, but we have to decide.
The instruction says "adding
and leading indentation" - we can add newlines anywhere, but we cannot remove characters. So we can insert newlines between any characters. So we can insert a newline after the space that follows '['. That way the space stays on the previous line, and the next line starts with 'client_id'. Then we can add indentation at the beginning of that line. So we can do that.
Similarly, after the comment, there is a space between the comment and 'azure'. We can insert a newline after that space? Actually the comment is "// config/services.php" and then a space then "'azure'". So we can insert a newline after the space? That would put the space at the end of the comment line, and the next line starts with "'azure'". That is fine. But we also need to consider that the comment is a full-line comment, so it should be on its own line. So we can put a newline after the comment text, but we have to keep the space? Actually we can put a newline right after the comment text, before the space. Then the space would be at the beginning of the next line. That would be a leading space. But we can add indentation before that space? That would give indentation then space. That is not ideal. Better to put the newline after the space, so the space stays on the comment line. But then the comment line would have a trailing space. That is acceptable. So we can do that.
So the strategy: we will insert newlines at appropriate places, and we will add indentation at the beginning of lines that need it. We will not remove any spaces. So we have to be careful.
Let's reconstruct the original string with spaces:
"// config/services.php 'azure' => [ 'client_id' => env('AZURE_CLIENT_ID'), 'client_secret' => env('AZURE_CLIENT_SECRET'), 'redirect' => env('AZURE_REDIRECT_URI'), 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant ], "
We need to break after the comment. The comment is "// config/services.php" and then a space. So we can put a newline after that space. So the first line becomes "// config/services.php " (with trailing space). Then the next line starts with "'azure' => [ ..." but we need to break inside the array.
We want the array elements on separate lines. So we need to break after the '[' and after each comma. But we have to keep spaces.
Let's break after the space that follows '['. So after "'azure' => [" there is a space. We can put a newline after that space. So the line with 'azure' becomes "'azure' => [ " (with trailing space). Then the next line starts with "'client_id' => env('AZURE_CLIENT_ID')," but we need to add indentation. We can add 4 spaces at the beginning of that line. But note that the original had a space after the '[' and then 'client_id'. So if we put a newline after that space, the next line starts with 'client_id' without a leading space. So we can add indentation.
Similarly, after the comma after env('AZURE_CLIENT_ID'), there is a space. We can put a newline after that space. So the line with client_id ends with a comma and a space? Actually the original has "env('AZURE_CLIENT_ID'), " - there is a comma then a space. So we can put a newline after that space. So the line becomes " 'client_id' => env('AZURE_CLIENT_ID'), " (with trailing space). Then the next line starts with "'client_secret' => ..." and we add indentation.
We continue similarly.
After the last element, we have "], " - there is a closing bracket and a space. We need to put the closing bracket on its own line? Typically we put it on a new line with no indentation or with the same indentation as the opening line. But we have to keep the space after the closing bracket? The original ends with "], " so there is a comma after the closing bracket? Actually it is "], " - that means closing bracket, then a comma? Wait, the original: "'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant ], " - so after the comment there is a space, then ']', then ','? Actually it is "], " - so it's closing bracket, then comma, then space. So the array is closed with ']' and then a comma. So we need to put the closing bracket on a new line. We can put a newline before the ']'? But we have to keep the space before it? The original has a space before the ']' because after the comment there is a space. So we can put a newline after the comment? Actually the comment is on the same line as the tenant entry. So we have " 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant " then a space then ']'? Actually the original: "'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant ], " - so after the comment there is a space, then ']', then ','. So we need to break before the ']'? We can put a newline after the comment? But the comment is part of the line. We want the closing bracket on its own line. So we can put a newline after the space that follows the comment. So the line with tenant ends with the comment and a space. Then the next line starts with ']' and then ','. But we need to add indentation? Typically the closing bracket is aligned with the opening line. The opening line starts at column 0? Actually the whole thing is a fragment. In a PHP config file, it might be inside a return array. But here we just have a fragment. So we can put the closing bracket at the same indentation level as the opening line. Since the opening line starts at column 0 (no indentation), we put the closing bracket at column 0. But we have to keep the comma after it. So we can put a newline before the ']' and then have '],' on that line. But we need to ensure we don't have extra spaces.
Let's plan the newlines:
Original string with spaces represented as ·:
//·config/services.php·'azure'·=>·[·'client_id'·=>·env('AZURE_CLIENT_ID'),·'client_secret'·=>·env('AZURE_CLIENT_SECRET'),·'redirect'·=>·env('AZURE_REDIRECT_URI'),·'tenant'·=>·env('AZURE_TENANT_ID',·'common'),·//·'common'·длÑ·multi-tenant·],·
We want to break after the first space after the comment? Actually the comment is "// config/services.php" - there is a space after the //? Actually it's "// config/services.php" - so after // there is a space, then config/services.php. So the comment text is "// config/services.php". Then there is a space before 'azure'. So we can put a newline after that space. So line1: "// config/services.php " (with trailing space). Then line2 starts with "'azure' => [ " but we need to break after the space after '['. So we can put a newline after that space. So line2: "'azure' => [ " (with trailing space). Then line3 starts with "'client_id' => env('AZURE_CLIENT_ID'), " but we need to break after the space after the comma. So we can put a newline after that space. So line3: " 'client_id' => env('AZURE_CLIENT_ID'), " (with indentation and trailing space). Then line4: " 'client_secret' => env('AZURE_CLIENT_SECRET'), " etc. Then line5: " 'redirect' => env('AZURE_REDIRECT_URI'), " Then line6: " 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant " - but we need to break after the comment? Actually we want the closing bracket on a new line. So we can put a newline after the space that follows the comment. So line6 ends with the comment and a space. Then line7: "]," - but we need to keep the comma. So line7: "]," but we have to consider that the original had a space before the ']'? Actually the space before ']' is after the comment. So we put a newline after that space, so the space stays on line6. Then line7 starts with ']' and then ','. So line7: "]," - but we need to add indentation? Since the opening line is at column 0, we put line7 at column 0. So no indentation.
But we also need to add indentation to lines 3-6. We'll add 4 spaces at the beginning of each of those lines.
Now, we must ensure we don't have extra spaces at the beginning of lines. Since we put newlines after spaces, the lines start with the next character. For line2, it starts with "'azure'", but we have a trailing space on line1. That's fine. For line3, it starts with "'client_id'", but we need to add indentation. So we add 4 spaces before that. So line3 becomes " 'client_id' => env('AZURE_CLIENT_ID'), " - but note that the original had a space after the comma? Actually after the comma there is a space, and we put a newline after that space, so the space is on line3? Wait, let's trace.
Original: ... env('AZURE_CLIENT_ID'), 'client_secret' ...
There is a comma, then a space, then 'client_secret'. If we put a newline after that space, then the space is on the line with client_id? Actually we put a newline after the space, so the space is before the newline? No, we insert a newline after the space. So the space remains on the previous line. So line3 would be " 'client_id' => env('AZURE_CLIENT_ID')," and then a space? Actually we have to decide where to put the newline. We can put the newline after the comma? But then the space would be at the beginning of the next line. That would be a leading space. To avoid that, we put the newline after the space. So the comma and the space are on the same line? Actually the comma is part of the expression, then a space, then we put a newline. So the line ends with a comma and a space? That would be a trailing space. That is acceptable. So line3: " 'client_id' => env('AZURE_CLIENT_ID'), " (with trailing space). Then line4 starts with "'client_secret' => ..." but we add indentation.
So we need to be consistent.
But we also have the comment inside the array. The comment is on the same line as the tenant entry. So we keep that.
Now, we need to output JSON with the code string. The code string should have real newlines. So we will construct it.
Let me write the code string with newlines:
Line1: "// config/services.php " (with trailing space)
Line2: "'azure' => [ " (with trailing space)
Line3: " 'client_id' => env('AZURE_CLIENT_ID'), " (with trailing space)
Line4: " 'client_secret' => env('AZURE_CLIENT_SECRET'), " (with trailing space)
Line5: " 'redirect' => env('AZURE_REDIRECT_URI'), " (with trailing space)
Line6: " 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant " (with trailing space)
Line7: "],"
But note that line6 has a trailing space after the comment. And line7 is "],". But we also need to consider that the original had a space before the ']'? Actually the space before ']' is after the comment. So we put a newline after that space, so the space is on line6. So line6 ends with a space. Then line7 starts with ']' and then ','. So line7 is "],". That is fine.
But we also need to ensure that the comment line is not too long? It's fine.
Now, we must not remove any characters. We have kept all spaces except we added newlines and indentation. We added indentation spaces at the beginning of lines 3-6. That is allowed. We also added a newline after the space on line1, after the space on line2, after the space after each comma, and after the space after the comment. We did not remove any spaces. So all original spaces are still there, but some are now at the end of lines (trailing spaces). That is acceptable.
But we need to check if we have any double spaces? For example, line1 ends with a space, and line2 starts with "'azure'" - no leading space. So that's fine. Line2 ends with a space, line3 starts with indentation (4 spaces) then "'client_id'" - so there is no extra space because the space after '[' is on line2. So line3 starts with indentation, then the content. That is fine.
Now, we need to output JSON. The code string will have newlines. We need to escape them as
in JSON.
So the JSON will be: {"code": "// config/services.php
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI'),
'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant
],
"}
But note that we have a trailing space at the end of each line except the last? Actually line7 has no trailing space. Also we have a newline at the end? The original had a space at the end? The original ended with "], " - so there was a space after the comma? Actually it was "], " - so after the comma there is a space. So we need to keep that space. In our line7 we have "]," but we need to include the space after the comma? The original had a space after the comma. So we should have "], " with a space. But we put a newline after the comma? Actually we didn't put a newline after the comma. We put a newline before the ']'? Let's see.
We have line6 ending with a space after the comment. Then we put a newline, then line7 starts with ']' and then ','. But the original had a space after the comma? Actually the original ends with "], " - so after the comma there is a space. So we need to include that space. So line7 should be "], " with a trailing space. But we also need to consider if there is any content after that? No. So we should have "], " and then a newline? Actually the original had a space at the very end. So we should keep that space. So line7 should be "], " (with trailing space). But then we might not need a newline after that because it's the end. But we can have a newline at the end? The instruction says "adding
" - we can add newlines. But we don't have to add a newline at the end. However, to be safe, we can include a newline at the end? But the original did not have a newline, it had a space. So we should keep the space and not add a newline. So the code string should end with "], " (space after comma). But we also have a newline before the ']'? Actually we have a newline after the space on line6. So line6 ends with a space, then newline, then line7 is "], " (with trailing space). So the code string ends with "], " and no newline at the end.
But we also need to consider that we added a newline after the space on line1, after the space on line2, etc. So the code string has newlines between lines.
Let me write the exact string with newlines:
Line1: "// config/services.php " (space at end)
Line2: "'azure' => [ " (space at end)
Line3: " 'client_id' => env('AZURE_CLIENT_ID'), " (space at end)
Line4: " 'client_secret' => env('AZURE_CLIENT_SECRET'), " (space at end)
Line5: " 'redirect' => env('AZURE_REDIRECT_URI'), " (space at end)
Line6: " 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant " (space at end)
Line7: "], " (space at end)
Now, we need to join them with newline characters. So the code string is:
"// config/services.php
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI'),
'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant
], "
But note that line6 ends with a space, then newline, then line7 starts with "], " - so there is a space after the comma. So the string ends with "], " (space after comma). That is correct.
Now, we need to ensure that we didn't miss any spaces. Let's compare with original.
Original: "// config/services.php 'azure' => [ 'client_id' => env('AZURE_CLIENT_ID'), 'client_secret' => env('AZURE_CLIENT_SECRET'), 'redirect' => env('AZURE_REDIRECT_URI'), 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant ], "
Our string: "// config/services.php
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI'),
'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant
], "
If we remove the newlines and the indentation spaces (the 4 spaces we added), we get:
"// config/services.php 'azure' => [ 'client_id' => env('AZURE_CLIENT_ID'), 'client_secret' => env('AZURE_CLIENT_SECRET'), 'redirect' => env('AZURE_REDIRECT_URI'), 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant ], "
But we have extra spaces? Let's see: after the comment we have a space, then newline, then 'azure' - but we have a space before the newline? Actually line1 ends with a space, then newline, then line2 starts with "'azure'" - so there is a space before the newline? That space is the one that was between the comment and 'azure'. So that is preserved. Similarly, after '[' we have a space, then newline, then indentation spaces, then 'client_id' - but the space after '[' is on line2, so that is preserved. The indentation spaces are added. So if we remove the newlines and the indentation spaces, we get the original with all spaces? Let's check: line1 has a space at end, line2 has a space at end, line3 has a space at end, etc. So if we concatenate without newlines, we get: "// config/services.php 'azure' => [ 'client_id' => env('AZURE_CLIENT_ID'), 'client_secret' => ..." - but we have extra spaces because we added indentation spaces. Actually we added 4 spaces at the beginning of lines 3-6. So if we remove those, we get the original. But we also have trailing spaces on each line. So if we remove newlines and the indentation spaces, we get the original with the same spaces? Let's simulate:
Original: "// config/services.php 'azure' => [ 'client_id' => env('AZURE_CLIENT_ID'), 'client_secret' => env('AZURE_CLIENT_SECRET'), 'redirect' => env('AZURE_REDIRECT_URI'), 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant ], "
Our string without newlines and without the added indentation (the 4 spaces at the beginning of lines 3-6) would be:
"// config/services.php 'azure' => [ 'client_id' => env('AZURE_CLIENT_ID'), 'client_secret' => env('AZURE_CLIENT_SECRET'), 'redirect' => env('AZURE_REDIRECT_URI'), 'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant ], "
But we have trailing spaces on each line? Actually if we remove newlines, the trailing spaces become spaces between tokens. For example, line1 ends with a space, then line2 starts with "'azure'" - so we have a space between the comment and 'azure'. That is correct. Line2 ends with a space, then line3 starts with indentation spaces? But we remove the indentation spaces, so line3 starts with "'client_id'" - but line2 ends with a space, so we have a space between '[' and 'client_id'. That is correct. Line3 ends with a space, then line4 starts with "'client_secret'" - so we have a space between the comma and 'client_secret'. That is correct. So all spaces are preserved. The only extra spaces are the indentation spaces we added, which we remove. So the string is equivalent to the original with the same characters except we added newlines and indentation. So that is allowed.
But we must ensure we didn't accidentally remove any spaces. We didn't.
Now, we need to output JSON. The code string contains double quotes? No, it contains single quotes and double quotes? Actually it has single quotes for strings, and double quotes? No, it has env('AZURE_CLIENT_ID') - single quotes. So no double quotes. So we can just put it in JSON.
But we need to escape backslashes? There are none. We need to escape newlines as
. So we will write the JSON with the code string containing
.
Also, we need to ensure that the JSON is valid. We'll output:
{"code": "// config/services.php
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI'),
'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant
], "}
But note that the string ends with a space after the comma. So we have "], " at the end. Also we have a space before the newline on each line? Actually we have a space before the newline because we put a space at the end of each line. So in the JSON string, we have "
" - that is a space then newline. That is fine.
But we need to be careful with the comment: it contains Cyrillic characters. That is fine in JSON as long as we encode properly. We'll just include them as is.
Now, let's write the final JSON.
But wait, the instruction says "Return JSON: {"code": "<reformatted text with real
>"}" - so we need to output a JSON object with a key "code". So we will do that.
I'll produce the JSON.<ï½endâofâthinkingï½>{"code": "// config/services.php
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI'),
'tenant' => env('AZURE_TENANT_ID', 'common'), // 'common' Ð´Ð»Ñ multi-tenant
], Контролер аутентифікації
class MicrosoftAuthController extends Controller
{
public function redirect(): RedirectResponse
{
return Socialite::driver('azure')
->scopes(['openid', 'profile', 'email', 'User.Read'])
->redirect();
}
public function callback(): RedirectResponse
{
try {
$msUser = Socialite::driver('azure')->user();
} catch (\Exception $e) {
return redirect('/login')->withErrors(['microsoft' => 'Помилка авторизації Microsoft']);
}
$user = User::updateOrCreate(
['azure_id' => $msUser->getId()],
[
'name' => $msUser->getName(),
'email' => $msUser->getEmail(),
'email_verified_at' => now(),
'azure_tenant_id' => $msUser->user['tid'] ?? null,
]
);
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}
} Чому при multi-tenant важливо валідувати tenant ID?
При single-tenant Azure сам обмежує коло користувачів, і перевірка tenant ID не обов'язкова. Однак при multi-tenant токен може бути виданий будь-якій організації — і якщо її tenant ID не додано до білого списку, зловмисник з іншої компанії отримає доступ. Валідація tenant ID — критичний крок для безпеки. На практиці ми стикалися з ситуаціями, коли розробники пропускали цю перевірку, і через місяць виявляли в системі користувачів з чужих організацій. Виправлення потім обходилося в 2-3 рази дорожче, ніж своєчасна валідація.
Multi-tenant: валідація тенанту
public function callback(): RedirectResponse
{
$msUser = Socialite::driver('azure')->user();
$tenantId = $msUser->user['tid'] ?? null;
$allowedTenants = explode(',', config('services.azure.allowed_tenants', ''));
if ($allowedTenants && !in_array($tenantId, $allowedTenants)) {
return redirect('/login')->withErrors([
'microsoft' => 'Ваша організація не має доступу до цього застосунку'
]);
}
// ...
} Отримання додаткових даних через MS Graph
$graphResponse = Http::withToken($msUser->token)
->get('https://graph.microsoft.com/v1.0/me', [
'$select' => 'id,displayName,mail,userPrincipalName,jobTitle,department,officeLocation',
]);
$profile = $graphResponse->json();
// $profile['jobTitle'] — посада
// $profile['department'] — підрозділ
// $profile['officeLocation']— офіс
// Отримання аватару
$photoResponse = Http::withToken($msUser->token)
->get('https://graph.microsoft.com/v1.0/me/photo/$value');
if ($photoResponse->ok()) {
Storage::disk('public')->put("avatars/{$user->id}.jpg", $photoResponse->body());
} SAML vs OAuth
Великі корпоративні клієнти можуть запитати підтримку SAML 2.0 замість OAuth. Azure AD підтримує обидва протоколи, але SAML потребує окремої бібліотеки та іншої архітектури. За нашими оцінками, впровадження OAuth в 2–3 рази швидше, ніж SAML, і значно простіше в підтримці. Рекомендуємо OAuth як основний протокол.
Що входить у роботу
При замовленні інтеграції Azure AD на сайті під ключ ви отримуєте:
- Документацію з конфігурації Azure (redirect URI, permissions, secrets).
- Реалізацію OAuth callback та зв'язування з обліковими записами користувачів.
- Інтеграцію MS Graph для отримання додаткових даних (аватар, посада, відділ).
- Валідацію tenant ID для multi-tenant сценаріїв.
- Тестування з реальним тенантом — підтверджуємо працездатність.
- Передачу доступів та навчання вашої команди.
Строки робіт
| Етап | Час |
|---|---|
| Реєстрація в Azure + налаштування дозволів | 0.5 дня |
| OAuth callback + зберігання tenant ID | 1.5 дня |
| MS Graph: додаткові дані, аватар | 1 день |
| Тести з реальним тенантом | 1 день |
Разом: 4–5 робочих днів. Вартість розраховується індивідуально після аналізу вашого проєкту. Замовте інтеграцію Azure AD — ми реалізуємо її за 4–5 робочих днів. Зв'яжіться з нами для оцінки вашого проєкту — ми підберемо оптимальне рішення під ваш стек та бізнес-вимоги.







