자습서: 백 엔드 API를 통해 App Service에서 Microsoft Graph로의 흐름 인증

프런트 엔드 앱의 사용자 자격 증명을 수락하도록 백 엔드 App Service를 만들고 구성한 다음, 해당 자격 증명을 다운스트림 Azure 서비스와 교환하는 방법을 알아봅니다. 이렇게 하면 사용자가 프런트 엔드 App Service에 로그인하고, 자격 증명을 백 엔드 App Service에 전달한 다음, 동일한 ID로 Azure 서비스에 액세스할 수 있습니다.

이 자습서에서는 다음을 하는 방법을 알아볼 수 있습니다.

  • 다운스트림 Azure 서비스에 대한 범위가 지정된 토큰을 제공하도록 백 엔드 인증 앱 구성
  • JavaScript 코드를 사용하여 로그인한 사용자의 액세스 토큰을 다운스트림 서비스에 대한 새 토큰으로 교환합니다.
  • JavaScript 코드를 사용하여 다운스트림 서비스에 액세스합니다.

필수 조건

이 자습서를 시작하기 전에 이전 자습서 보안 JavaScript 앱에서 Microsoft Graph에 액세스를 완료하되, 자습서 끝 부분의 리소스는 제거하지 마세요. 이 자습서에서는 두 개의 App Services와 해당 인증 앱이 있다고 가정합니다.

이전 자습서에서는 Azure Cloud Shell을 Azure CLI의 셸로 사용했습니다. 이 자습서에서는 계속 이렇게 사용합니다.

아키텍처

이 자습서에서는 프런트 엔드 앱에서 제공한 사용자 자격 증명을 백 엔드 앱에 전달한 다음 Azure 서비스에 전달하는 방법을 보여 줍니다. 이 자습서에서 다운스트림 서비스는 Microsoft Graph입니다. 사용자의 자격 증명은 Microsoft Graph에서 프로필을 가져오는 데 사용됩니다.

Architectural image of App Service connecting to App Service connecting to Microsoft Graph on behalf of a signed-in user.

사용자가 이 아키텍처에서 Microsoft Graph 정보를 가져올 수 있는 인증 흐름:

이전 자습서에서 다룬 내용:

  1. Active Directory를 ID 공급자로 사용하도록 구성된 프런트 엔드 App Service에 사용자를 로그인합니다.
  2. 프런트 엔드 App Service는 사용자의 토큰을 백 엔드 App Service에 전달합니다.
  3. 백 엔드 앱은 프런트 엔드가 API 요청을 만들 수 있도록 보호됩니다. 사용자의 액세스 토큰에는 백 엔드 API 및 user_impersonation의 범위에 대한 대상 그룹이 있습니다.
  4. 백 엔드 앱 등록에 범위가 User.Read인 Microsoft Graph가 이미 있습니다. 기본적으로 모든 앱 등록에 추가됩니다.
  5. 이전 자습서의 끝 부분에서 Graph가 연결되지 않았기 때문에 가짜 프로필이 프런트 엔드 앱에 반환되었습니다.

이 자습서에서는 아키텍처를 확장합니다.

  1. 백 엔드 앱에 대한 사용자 동의 화면을 무시하도록 관리자 동의를 승인합니다.
  2. 애플리케이션 코드를 변경하여 프런트 엔드 앱에서 보낸 액세스 토큰을 Microsoft Graph에 필요한 권한이 있는 액세스 토큰으로 변환합니다.
  3. Microsoft Graph와 같은 다운스트림 Azure 서비스의 범위를 사용하여 백 엔드 앱에서 새 토큰으로 토큰을 교환하도록 하는 코드를 제공합니다.
  4. 백 엔드 앱에서 새 토큰을 사용하여 현재 인증 사용자로 다운스트림 서비스에 액세스할 수 있는 코드를 제공합니다.
  5. az webapp up을 사용하여 백 엔드 앱을 재배포합니다.
  6. 이 자습서의 끝 부분에는 그래프가 연결되어 있기 때문에 실제 프로필이 프런트 엔드 앱으로 반환됩니다.

이 자습서에서는 다음을 수행하지 않습니다.

  • 이전 자습서의 프런트 엔드 앱을 변경하지 않습니다.
  • User.Read는 기본적으로 모든 인증 앱에 추가되므로 백 엔드 인증 앱의 범위 권한을 변경하지 않습니다.

이전 자습서에서는 사용자가 프런트 엔드 앱에 로그인했을 때 사용자 동의를 요청하는 팝업이 표시되었습니다.

이 자습서에서는 Microsoft Graph에서 사용자 프로필을 읽기 위해 백 엔드 앱이 로그인한 사용자의 액세스 토큰을 새 액세스 토큰과 Microsoft Graph에 필요한 권한으로 교환해야 합니다. 사용자는 백 엔드 앱에 직접 연결되지 않으므로 동의 화면에 대화형으로 액세스할 수 없습니다. 관리자 동의를 승인하려면 Microsoft Entra ID에서 백 엔드 앱의 앱 등록을 구성하여 이 문제를 해결해야 합니다. 이는 일반적으로 Active Directory 관리자가 수행하는 설정 변경입니다.

  1. Azure Portal을 열고 백 엔드 App Service에 대한 연구를 검색합니다.

  2. 설정 -> 인증 섹션을 찾습니다.

  3. ID 공급자를 선택하여 인증 앱으로 이동합니다.

  4. 인증 앱에서 관리 -> API 권한을 선택합니다.

  5. 기본 디렉터리에 대한 관리자 동의 부여를 선택합니다.

    Screenshot of Azure portal authentication app with admin consent button highlighted.

  6. 팝업 창에서 를 선택하여 동의를 확인합니다.

  7. 상태 열에 기본 디렉터리에 대해 부여됨이 표시되는지 확인합니다. 이 설정을 사용하면 백 엔드 앱이 더 이상 로그인한 사용자에게 동의 화면을 표시할 필요 없이 액세스 토큰을 직접 요청할 수 있습니다. 로그인한 사용자는 User.Read 범위 설정에 액세스할 수 있습니다. 이 범위는 앱 등록이 생성되는 기본 범위이기 때문입니다.

    Screenshot of Azure portal authentication app with admin consent granted in status column.

2. npm 패키지 설치

이전 자습서에서는 Azure Portal ID 공급자를 구성하여 유일한 인증을 제공했기 때문에 백 엔드 앱에 인증을 위한 npm 패키지가 필요하지 않았습니다. 이 자습서에서는 로그인한 사용자의 백 엔드 API에 대한 액세스 토큰을 해당 범위의 Microsoft Graph와 액세스 토큰으로 교환해야 합니다. 이 교환은 더 이상 App Service 인증을 사용하지 않지만 Microsoft Entra ID 및 MSAL.js를 직접 사용하기 때문에 두 개의 라이브러리로 완료됩니다.

  1. Azure Cloud Shell을 열고 샘플 디렉터리의 백 엔드 앱으로 변경:

    cd js-e2e-web-app-easy-auth-app-to-app/backend
    
  2. Azure MSAL npm 패키지 설치:

    npm install @azure/msal-node
    
  3. Microsoft Graph npm 패키지 설치:

    npm install @microsoft/microsoft-graph-client
    

3. 현재 토큰을 Microsoft Graph 토큰으로 교환하는 코드 추가

이 단계를 완료하기 위한 소스 코드가 제공됩니다. 다음 단계를 사용하여 이 코드를 포함합니다.

  1. ./src/server.js 파일을 엽니다.

  2. 파일 맨 위에서 다음 종속성의 주석 처리 제거:

    import { getGraphProfile } from './with-graph/graph';
    
  3. 동일한 파일에서 graphProfile 변수의 주석 처리 제거:

    let graphProfile={};
    
  4. 동일한 파일에서 get-profile 경로의 다음 getGraphProfile 줄의 주석 처리를 제거하여 Microsoft Graph에서 프로필 가져오기:

    // where did the profile come from
    profileFromGraph=true;
    
    // get the profile from Microsoft Graph
    graphProfile = await getGraphProfile(accessToken);
    
    // log the profile for debugging
    console.log(`profile: ${JSON.stringify(graphProfile)}`);
    
  5. 변경 내용 저장: Ctrl + s.

  6. 백 엔드 앱 재배포:

    az webapp up --resource-group myAuthResourceGroup --name <back-end-app-name> 
    
    

4. 백 엔드 코드를 검사하여 백 엔드 API 토큰을 Microsoft Graph 토큰으로 교환

백 엔드 API 대상 그룹 토큰을 Microsoft Graph 토큰으로 변경하려면 백 엔드 앱이 테넌트 ID를 찾고 이를 사용하여 MSAL.js 구성 개체의 일부로 사용해야 합니다. Microsoft를 ID 공급자로 구성한 백 엔드 앱은 테넌트 ID 및 기타 몇몇 필수 값이 이미 App Service 앱 설정에 있습니다.

샘플 앱에는 이미 다음 코드가 제공되어 있습니다. 이 코드가 있는 이유와 작동 방식을 이해하여 빌드하는 다른 앱에 이 동일한 기능이 필요한 경우 이 작업을 적용할 수 있도록 해야 합니다.

테넌트 ID를 가져오기 위한 코드 검사

  1. ./backend/src/with-graph/auth.js 파일을 엽니다.

  2. getTenantId() 함수를 검토합니다.

    export function getTenantId() {
    
        const openIdIssuer = process.env.WEBSITE_AUTH_OPENID_ISSUER;
        const backendAppTenantId = openIdIssuer.replace(/https:\/\/sts\.windows\.net\/(.{1,36})\/v2\.0/gm, '$1');
    
        return backendAppTenantId;
    }
    
  3. 이 함수는 WEBSITE_AUTH_OPENID_ISSUER 환경 변수에서 현재 테넌트 ID를 가져옵니다. ID는 정규식을 사용하여 변수에서 구문 분석됩니다.

코드를 검사하여 MSAL.js를 사용하여 Graph 토큰 가져오기

  1. ./backend/src/with-graph/auth.js 파일에서 getGraphToken() 함수를 검토합니다.

  2. MSAL.js 구성 개체를 빌드하고 MSAL 구성을 사용하여 clientCredentialAuthority를 만듭니다. on-behalf-off 요청을 구성합니다. 그런 다음 acquireTokenOnBehalfOf를 사용하여 백 엔드 API 액세스 토큰을 Graph 액세스 토큰으로 교환합니다.

    // ./backend/src/auth.js
    // Exchange current bearerToken for Graph API token
    // Env vars were set by App Service
    export async function getGraphToken(backEndAccessToken) {
    
        const config = {
            // MSAL configuration
            auth: {
                // the backend's authentication CLIENT ID 
                clientId: process.env.WEBSITE_AUTH_CLIENT_ID,
                // the backend's authentication CLIENT SECRET 
                clientSecret: process.env.MICROSOFT_PROVIDER_AUTHENTICATION_SECRET,
                // OAuth 2.0 authorization endpoint (v2)
                // should be: https://login.microsoftonline.com/BACKEND-TENANT-ID
                authority: `https://login.microsoftonline.com/${getTenantId()}`
            },
            // used for debugging
            system: {
                loggerOptions: {
                    loggerCallback(loglevel, message, containsPii) {
                        console.log(message);
                    },
                    piiLoggingEnabled: true,
                    logLevel: MSAL.LogLevel.Verbose,
                }
            }
        };
    
        const clientCredentialAuthority = new MSAL.ConfidentialClientApplication(config);
    
        const oboRequest = {
            oboAssertion: backEndAccessToken,
            // this scope must already exist on the backend authentication app registration 
            // and visible in resources.azure.com backend app auth config
            scopes: ["https://graph.microsoft.com/.default"]
        }
    
        // This example has App service validate token in runtime
        // from headers that can't be set externally
    
        // If you aren't using App service's authentication, 
        // you must validate your access token yourself
        // before calling this code
        try {
            const { accessToken } = await clientCredentialAuthority.acquireTokenOnBehalfOf(oboRequest);
            return accessToken;
        } catch (error) {
            console.log(`getGraphToken:error.type = ${error.type}  ${error.message}`);
        }
    }
    

5. 백 엔드 코드를 검사하여 새 토큰으로 Microsoft Graph에 액세스

프런트 엔드 애플리케이션에 로그인한 사용자로 Microsoft Graph에 액세스할 수 있도록 변경된 내용은 다음과 같습니다.

  • User.Read의 필요한 범위를 사용하여 다운스트림 서비스인 Microsoft Graph에 대한 API 권한으로 Active Directory 앱 등록을 구성합니다.
  • 백 엔드 앱에 대한 사용자 동의 화면을 무시하도록 관리자 동의를 승인합니다.
  • 애플리케이션 코드를 변경하여 프런트 엔드 앱에서 보낸 액세스 토큰을 다운스트림 서비스인 Microsoft Graph에 필요한 권한이 있는 액세스 토큰으로 변환합니다.

이제 코드에 Microsoft Graph에 대한 올바른 토큰이 있으므로 이 토큰을 사용하여 Microsoft Graph에 클라이언트를 만든 다음, 사용자의 프로필을 가져옵니다.

  1. ./backend/src/graph.js 열기

  2. getGraphProfile() 함수에서 토큰을 가져옵니다. 그런 다음 토큰에서 인증된 클라이언트를 가져온 후 프로필을 가져옵니다.

    // 
    import graph from "@microsoft/microsoft-graph-client";
    import { getGraphToken } from "./auth.js";
    
    // Create client from token with Graph API scope
    export function getAuthenticatedClient(accessToken) {
        const client = graph.Client.init({
            authProvider: (done) => {
                done(null, accessToken);
            }
        });
    
        return client;
    }
    export async function getGraphProfile(accessToken) {
        // exchange current backend token for token with 
        // graph api scope
        const graphToken = await getGraphToken(accessToken);
    
        // use graph token to get Graph client
        const graphClient = getAuthenticatedClient(graphToken);
    
        // get profile of user
        const profile = await graphClient
            .api('/me')
            .get();
    
        return profile;
    }
    

6. 변경 내용 테스트

  1. 브라우저에서 프런트 엔드 웹 사이트를 사용합니다. URL은 https://<front-end-app-name>.azurewebsites.net/ 형식입니다. 토큰이 만료된 경우 토큰을 새로 고쳐야 할 수 있습니다.

  2. Get user's profile를 선택합니다. 이는 전달자 토큰의 인증을 백 엔드로 전달합니다.

  3. 백 엔드는 계정의 실제 Microsoft Graph 프로필로 응답합니다.

    Screenshot of web browser showing frontend application after successfully getting real profile from backend app.

7. 정리

이전 단계에서는 리소스 그룹에서 Azure 리소스를 만들었습니다.

  1. Cloud Shell에서 다음 명령을 실행하여 리소스 그룹을 삭제합니다. 이 명령을 실행하는 데 1분 정도 걸릴 수 있습니다.

    az group delete --name myAuthResourceGroup
    
  2. 이전에 백 엔드 및 프런트 엔드 앱에 대한 Enable authentication and authorization 섹션에서 찾아서 기록한 인증 앱의 클라이언트 ID를 사용합니다.

  3. 프런트 엔드 및 백 엔드 앱 모두에 대한 앱 등록을 삭제합니다.

    # delete app - do this for both frontend and backend client ids
    az ad app delete <client-id>
    

자주 묻는 질문

80049217 오류가 발생했습니다. 어떤 의미인가요?

이 오류(CompactToken parsing failed with error code: 80049217)는 백 엔드 App Service가 Microsoft Graph 토큰을 반환할 권한이 없음을 의미합니다. 이 오류는 앱 등록에 User.Read 권한이 없기 때문에 발생합니다.

AADSTS65001 오류가 발생했습니다. 어떤 의미인가요?

이 오류(AADSTS65001: The user or administrator has not consented to use the application with ID \<backend-authentication-id>. Send an interactive authorization request for this user and resource)는 백 엔드 인증 앱이 관리자 동의가 가능하게 구성되지 않았음을 의미합니다. 오류는 백 엔드 앱의 로그에 표시되므로 프런트 엔드 애플리케이션은 프런트 엔드 앱에서 프로필이 보이지 않는 이유를 사용자에게 알릴 수 없습니다.

다른 다운스트림 Azure 서비스에 사용자로 연결하려면 어떻게 하나요?

이 자습서에서는 Microsoft Graph에 인증된 API 앱을 보여 줍니다. 그러나 동일한 일반 단계를 적용하면 사용자를 대신하여 모든 Azure 서비스에 액세스할 수 있습니다.

  1. 프런트 엔드 애플리케이션은 변경되지 않습니다. 백 엔드의 인증 앱 등록 및 백 엔드 앱 소스 코드만 변경됩니다.
  2. 백 엔드 API로 범위가 지정된 사용자의 토큰을 액세스하려는 다운스트림 서비스에 대한 토큰으로 교환합니다.
  3. 다운스트림 서비스의 SDK에서 토큰을 사용하여 클라이언트를 만듭니다.
  4. 다운스트림 클라이언트를 사용하여 서비스 기능에 액세스합니다.

다음 단계