Share via


MSAL.js를 사용한 Single Sign-On

SSO(Single Sign-On)는 사용자에게 자격 증명을 요청하는 횟수를 줄임으로써 보다 원활한 환경을 제공합니다. 사용자가 자격 증명을 한 번 입력하면 추가로 메시지를 표시하지 않고 동일한 디바이스의 다른 애플리케이션에서 설정된 세션을 다시 사용할 수 있습니다.

Microsoft Entra ID는 사용자가 처음으로 인증할 때 세션 쿠키를 설정하여 SSO를 사용하도록 설정합니다. 또한 MSAL.js는 애플리케이션 도메인당 브라우저 스토리지에서 사용자의 ID 토큰 및 액세스 토큰을 캐시합니다. Microsoft Entra 세션 쿠키와 MSAL(Microsoft 인증 라이브러리) 캐시의 두 메커니즘은 서로 독립적이지만 함께 작동하여 SSO 동작을 제공합니다.

동일한 앱에 대한 브라우저 탭 간 SSO

사용자가 여러 탭에서 애플리케이션을 열고 그중 하나에 로그인하면 프롬프트 없이 다른 탭에서 열려 있는 동일한 앱에 로그인할 수 있습니다. 이렇게 하려면 다음 예와 같이 MSAL.js 구성 개체의 cacheLocationlocalStorage로 설정해야 합니다.

const config = {
  auth: {
    clientId: "1111-2222-3333-4444-55555555",
  },
  cache: {
    cacheLocation: "localStorage",
  },
};

const msalInstance = new msal.PublicClientApplication(config);

이 경우 서로 다른 브라우저 탭의 애플리케이션 인스턴스가 동일한 MSAL 캐시를 사용하므로 인스턴스 간에 인증 상태를 공유합니다. 사용자가 다른 브라우저 탭 또는 창에서 로그인할 때 MSAL 이벤트를 사용하여 애플리케이션 인스턴스를 업데이트할 수도 있습니다. 자세한 내용은 탭 및 창에서 로그인 상태 동기화를 참조하세요.

여러 앱 간 SSO

사용자가 인증하면 세션 쿠키가 브라우저의 Microsoft Entra 도메인에 설정됩니다. MSAL.js는 이 세션 쿠키를 사용하여 서로 다른 애플리케이션 간에 사용자에 대한 SSO를 제공합니다. 특히, MSAL.js는 사용자를 로그인되게 하고 상호 작용 없이 토큰을 가져오기 위한 ssoSilent 메서드를 제공합니다. 그러나 사용자가 Microsoft Entra ID 세션에서 여러 사용자 계정을 가지고 있는 경우 로그인할 계정을 선택하라는 메시지가 표시됩니다. 따라서 ssoSilent 메서드를 사용하여 SSO를 달성하는 방법에는 두 가지가 있습니다.

사용자 힌트 사용

성능을 개선하고 권한 부여 서버가 올바른 계정 세션을 찾을 수 있도록 하려면 ssoSilent 메서드의 요청 개체에서 다음 옵션 중 하나를 전달하여 토큰을 자동으로 가져올 수 있습니다.

자동 및 대화형 요청에서 가장 신뢰할 수 있는 계정 힌트이므로 login_hint로 제공된 ssoSilent선택적 ID 토큰 클레임loginHint을 사용하는 것이 좋습니다.

로그인 힌트 사용

선택적 클레임은 login_hint 로그인을 시도하는 사용자 계정에 대한 Microsoft Entra ID 힌트를 제공합니다. 대화형 인증 요청 중에 일반적으로 표시되는 계정 선택 프롬프트를 무시하려면 다음과 같이 loginHint를 제공합니다.

const silentRequest = {
    scopes: ["User.Read", "Mail.Read"],
    loginHint: "user@contoso.com"
};

try {
    const loginResponse = await msalInstance.ssoSilent(silentRequest);
} catch (err) {
    if (err instanceof InteractionRequiredAuthError) {
        const loginResponse = await msalInstance.loginPopup(silentRequest).catch(error => {
            // handle error
        });
    } else {
        // handle error
    }
}

이 예제 loginHint 에서는 대화형 토큰 요청 중에 힌트로 사용되는 사용자의 이메일 또는 UPN을 포함합니다. 애플리케이션 간에 힌트를 전달하여 자동 SSO를 용이하게 할 수 있습니다. 여기서 애플리케이션 A는 사용자를 로그인하고 loginHint를 읽은 다음 클레임 및 현재 테넌트 컨텍스트를 애플리케이션 B에 보냅니다. Microsoft Entra ID는 로그인 양식을 미리 채우거나 계정 선택 프롬프트를 무시하고 지정된 사용자에 대한 인증 프로세스를 직접 진행하려고 시도합니다.

login_hint 클레임의 정보가 기존 사용자와 일치하지 않는 경우 계정 선택을 포함하여 표준 로그인 환경을 진행하도록 리디렉션됩니다.

세션 ID 사용

세션 ID를 사용하려면 sid선택적 클레임으로 앱의 ID 토큰에 추가합니다. sid 클레임을 사용하면 애플리케이션에서 계정 이름 또는 사용자 이름과 관계없이 사용자의 Microsoft Entra 세션을 식별할 수 있습니다. sid와 같은 선택적 클레임을 추가하는 방법에 대한 자세한 내용은 앱에 선택적 클레임 제공을 참조하세요. MSAL.js에서 ssoSilent를 통해 수행하는 자동 인증 요청에서 SID(세션 ID)를 사용합니다.

const request = {
  scopes: ["user.read"],
  sid: sid,
};

 try {
    const loginResponse = await msalInstance.ssoSilent(request);
} catch (err) {
    if (err instanceof InteractionRequiredAuthError) {
        const loginResponse = await msalInstance.loginPopup(request).catch(error => {
            // handle error
        });
    } else {
        // handle error
    }
}

계정 개체 사용

사용자 계정 정보를 알고 있는 경우 getAccountByUsername() 또는 getAccountByHomeId() 메서드를 사용하여 사용자 계정을 검색할 수도 있습니다.

const username = "test@contoso.com";
const myAccount  = msalInstance.getAccountByUsername(username);

const request = {
    scopes: ["User.Read"],
    account: myAccount
};

try {
    const loginResponse = await msalInstance.ssoSilent(request);
} catch (err) {
    if (err instanceof InteractionRequiredAuthError) {
        const loginResponse = await msalInstance.loginPopup(request).catch(error => {
            // handle error
        });
    } else {
        // handle error
    }
}

사용자 힌트 없음

다음 코드와 같이 account, sid 또는 login_hint를 전달하지 않고 ssoSilent 메서드를 사용하려고 시도할 수 있습니다.

const request = {
    scopes: ["User.Read"]
};

try {
    const loginResponse = await msalInstance.ssoSilent(request);
} catch (err) {
    if (err instanceof InteractionRequiredAuthError) {
        const loginResponse = await msalInstance.loginPopup(request).catch(error => {
            // handle error
        });
    } else {
        // handle error
    }
}

그러나 애플리케이션에서 단일 브라우저 세션에 여러 사용자가 있는 경우 또는 사용자에게 해당 단일 브라우저 세션에 대한 여러 계정이 있는 경우 자동 로그인 오류가 발생할 수 있습니다. 여러 계정을 사용할 수 있는 경우 다음 오류가 표시될 수 있습니다.

InteractionRequiredAuthError: interaction_required: AADSTS16000: Either multiple user identities are available for the current request or selected account is not supported for the scenario.

이 오류는 서버가 로그인할 계정을 결정할 수 없음을 나타내며 계정을 선택하려면 이전 예의 매개변수(account, login_hint, sid) 중 하나 또는 대화형 로그인이 필요합니다.

ssoSilent 사용 시 고려 사항

리디렉션 URI(회신 URL)

성능을 향상하고 문제를 방지하려면 redirectUri를 빈 페이지 또는 MSAL을 사용하지 않는 다른 페이지로 설정합니다.

  • 애플리케이션이 팝업 및 자동 메서드만 사용하는 경우 PublicClientApplication 구성 개체에서 redirectUri를 설정합니다.
  • 애플리케이션이 리디렉션 메서드도 사용하는 경우 요청별로 redirectUri를 설정합니다.

타사 쿠키

ssoSilent는 숨겨진 iframe을 열고 Microsoft Entra ID에서 기존 세션을 다시 사용하려고 합니다. 이는 Safari와 같은 타사 쿠키를 차단하는 브라우저에서 작동하지 않으며 상호 작용 오류를 초래합니다.

InteractionRequiredAuthError: login_required: AADSTS50058: A silent sign-in request was sent but no user is signed in. The cookies used to represent the user's session were not sent in the request to Azure AD

오류를 해결하려면 사용자가 loginPopup() 또는 loginRedirect()를 사용하여 대화형 인증 요청을 만들어야 합니다. 경우에 따라 프롬프트 값 없음을 대화형 MSAL.js 메서드와 함께 사용하여 SSO를 달성할 수 있습니다. 자세한 내용은 prompt=none이 있는 대화형 요청을 참조하세요. 사용자의 로그인 정보가 이미 있는 경우에는 loginHint 또는 sid 선택적 매개 변수를 전달하여 특정 계정을 로그인되게 할 수 있습니다.

prompt=login을 사용하여 SSO 부정

권한 부여 서버와의 활성 세션에도 불구하고 Microsoft Entra ID에서 사용자에게 자격 증명을 입력하라는 메시지를 표시하도록 하려면 MSAL.js 요청에서 login 프롬프트 매개 변수를 사용할 수 있습니다. 자세한 내용은 MSAL.js 프롬프트 동작을 참조하세요.

ADAL.js와 MSAL.js 간에 인증 상태 공유

MSAL.js는 Microsoft Entra 인증 시나리오에 대한 ADAL.js의 기능 패리티를 제공합니다. ADAL.js에서 MSAL.js로 쉽게 마이그레이션하고 앱 간에 인증 상태를 공유하기 위해 라이브러리가 ADAL.js 캐시에서 사용자의 세션을 나타내는 ID 토큰을 읽습니다. ADAL.js에서 마이그레이션할 때 이것을 활용하려면 라이브러리에서 토큰을 캐싱하는 데 localStorage를 사용하고 있는지 확인해야 합니다. 다음과 같이 초기화할 때 MSAL.js 및 ADAL.js 구성 모두에서 cacheLocationlocalStorage로 설정합니다.


// In ADAL.js
window.config = {
  clientId: "1111-2222-3333-4444-55555555",
  cacheLocation: "localStorage",
};

var authContext = new AuthenticationContext(config);

// In latest MSAL.js version
const config = {
  auth: {
    clientId: "1111-2222-3333-4444-55555555",
  },
  cache: {
    cacheLocation: "localStorage",
  },
};

const msalInstance = new msal.PublicClientApplication(config);

다음 단계

SSO에 대한 자세한 내용은 다음을 참조하세요.