FedCM 업데이트: Continuation API 번들 및 Storage Access API 자동 부여의 오리진 트라이얼

Chrome 126부터 개발자는 일부 승인 사용 사례를 지원하는 데스크톱 Federated Credential Management API (FedCM) 기능 번들의 오리진 트라이얼을 실행할 수 있습니다. 번들은 Continuation API와 Parameters API로 구성되며 ID 공급업체 (IdP)에서 제공하는 권한 대화상자가 포함된 OAuth 승인 흐름과 유사한 환경을 지원합니다. 번들에는 필드 API, 여러 configURL, 맞춤 계정 라벨과 같은 기타 변경사항도 포함되어 있습니다. Chrome 126부터 사용자가 이전에 FedCM을 사용하여 성공적으로 로그인한 경우 SAA 요청을 자동으로 부여하는 Storage Access API (SAA)의 오리진 트라이얼도 도입됩니다.

오리진 트라이얼: FedCM Continuation API 번들

FedCM Continuation API 번들은 여러 FedCM 확장 프로그램으로 구성됩니다.

연속 API

사용자가 RP에 로그인한 후 버튼 모드를 통해 승인합니다.

Glitch에서 API 데모를 확인할 수 있습니다.

Continuation API는 IdP의 ID 어설션 엔드포인트가 사용자가 다단계 로그인 과정을 계속할 수 있도록 FedCM이 렌더링할 URL을 선택적으로 반환할 수 있게 해줍니다. 이렇게 하면 IdP가 사용자에게 기존 FedCM UI에서 가능한 것 이상의 권한 (예: 사용자의 서버 측 리소스에 대한 액세스)을 부여하도록 요청할 수 있습니다.

일반적으로 ID 어설션 엔드포인트는 인증에 필요한 토큰을 반환합니다.

{
  "token": "***********"
}

하지만 Continuation API를 사용하면 ID 어설션 엔드포인트가 ID 어설션 엔드포인트에 대한 절대 경로 또는 상대 경로가 포함된 continue_on 속성을 반환할 수 있습니다.

{
  // In the id_assertion_endpoint, instead of returning a typical
  // "token" response, the IdP decides that it needs the user to
  // continue on a pop-up window:
  "continue_on": "/oauth/authorize?scope=..."
}

브라우저가 continue_on 응답을 수신하자마자 새 팝업 창이 열리고 사용자를 지정된 경로로 이동합니다.

사용자가 페이지와 상호작용하면(예: RP와 추가 정보를 공유할 수 있는 추가 권한 부여) IdP 페이지는 IdentityProvider.resolve()를 호출하여 원래의 navigator.credentials.get() 호출을 해결하고 토큰을 인수로 반환할 수 있습니다.

document.getElementById('allow_btn').addEventListener('click', async () => {
  let accessToken = await fetch('/generate_access_token.cgi');
  // Closes the window and resolves the promise (that is still hanging
  // in the relying party's renderer) with the value that is passed.
  IdentityProvider.resolve(accessToken);
});

그러면 브라우저가 팝업을 자체적으로 닫고 API 호출자에게 토큰을 반환합니다.

사용자가 요청을 거부하면 IdentityProvider.close()를 호출하여 창을 닫을 수 있습니다.

IdentityProvider.close();

어떤 이유로든 사용자가 팝업에서 계정을 변경한 경우(예: IdP가 '사용자 전환' 기능을 제공하거나 위임 사례인 경우) 확인 호출은 다음과 같은 두 번째 인수(선택사항)를 허용합니다.

IdentityProvider.resolve(token, {accountId: '1234');

매개변수 API

Parameters API를 사용하면 RP가 ID 어설션 엔드포인트에 추가 매개변수를 제공할 수 있습니다. Parameters API를 사용하면 RP가 추가 매개변수를 IdP에 전달하여 기본 로그인 이상의 리소스에 대한 권한을 요청할 수 있습니다. 사용자는 Continuation API를 통해 실행되는 IdP 제어 UX 흐름을 통해 이러한 권한을 승인합니다.

API를 사용하려면 params 속성에 매개변수를 navigator.credentials.get() 호출의 객체로 추가합니다.

let {token} = await navigator.credentials.get({
  identity: {
    providers: [{
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      // Key/value pairs that need to be passed from the
      // RP to the IdP but that don't really play any role with
      // the browser.
      params: {
        IDP_SPECIFIC_PARAM: '1',
        foo: 'BAR',
        ETC: 'MOAR',
        scope: 'calendar.readonly photos.write',
      }
    },
  }
});

params 객체의 속성 이름 앞에 param_가 추가됩니다. 위의 예에서 params 속성에는 IDP_SPECIFIC_PARAM'1'으로, foo'BAR'으로, ETC'MOAR'로, scope'calendar.readonly photos.write'로 포함됩니다. 이는 요청의 HTTP 본문에서 param_IDP_SPECIFIC_PARAM=1&param_foo=BAR&param_ETC=MOAR&param_scope=calendar.readonly%20photos.write로 변환됩니다.

POST /fedcm_assertion_endpoint HTTP/1.1
Host: idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=false&param_IDP_SPECIFIC_PARAM=1&param_foo=BAR&param_ETC=MOAR&param_scope=calendar.readonly%20photos.write

동적으로 권한 가져오기

일반적으로 사용자는 개발자가 구현하기가 가장 쉽다고 느낄 때가 아니라 필요할 때 권한을 요청하는 것이 가장 좋습니다. 예를 들어, 사용자가 사진을 찍으려고 할 때 카메라 액세스 권한을 요청하는 것이 사용자가 웹사이트에 방문하자마자 권한을 요청하는 것보다 더 좋습니다. 서버 리소스도 마찬가지입니다. 사용자에게 필요할 때만 권한을 요청합니다. 이를 '동적 승인'이라고 합니다.

FedCM을 사용하여 동적으로 승인을 요청하기 위해 IdP는 다음을 수행할 수 있습니다.

  1. IdP가 이해할 수 있는 필수 매개변수(예: scope)를 사용하여 navigator.credentials.get()를 호출합니다.
  2. ID 어설션 엔드포인트는 사용자가 이미 로그인되어 있는지 확인하고 continue_on URL로 응답합니다.
  3. 브라우저에서 요청된 범위와 일치하는 추가 권한을 요청하는 IdP의 권한 페이지가 있는 팝업 창을 엽니다.
  4. IdP에서 IdentityProvider.resolve()를 통해 승인하면 창이 닫히고 RP의 원래 navigator.credentials.get() 호출은 관련 토큰 또는 승인 코드를 가져오므로 RP가 이를 적절한 액세스 토큰과 교환할 수 있습니다.

필드 API

Fields API를 사용하면 RP가 IdP에서 요청할 계정 속성을 선언할 수 있으므로 브라우저가 FedCM 대화상자에서 적절한 공개 UI를 렌더링할 수 있습니다. 반환된 토큰에 요청된 필드를 포함하는 것은 IdP의 책임입니다. OpenID Connect에서 '기본 프로필'을 요청하는 반면 OAuth의 '범위'를 요청하는 것을 고려해 보세요.

위젯 모드의 공개 메시지
위젯 모드의 공개 메시지
버튼 모드의 메시지 공개
버튼 모드의 공개 메시지

Field API를 사용하려면 fields 속성에 매개변수를 navigator.credentials.get() 호출의 배열로 추가합니다. 현재는 이 필드에 'name', 'email', 'picture'가 포함될 수 있지만 향후 더 많은 값을 포함하도록 확장할 수 있습니다.

fields를 사용한 요청은 다음과 같습니다.

let { token } = await navigator.credentials.get({
  identity: {
    providers: [{
      fields: ['name', 'email', 'picture'],
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      params: {
        scope: 'drive.readonly calendar.readonly',
      }
    },
  }
  mediation: 'optional',
});

ID 어설션 엔드포인트에 대한 HTTP 요청에는 RP 지정 fields 매개변수가 포함되며, 재사용자가 아닌 경우 true로 설정된 disclosure_text_shown 매개변수와 브라우저가 disclosure_shown_for 매개변수에서 사용자에게 공개한 필드가 포함됩니다.

POST /id_assertion_endpoint HTTP/1.1
Host: idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=true&fields=email,name,picture&disclosure_shown_for=email,name,picture

RP가 IdP의 추가 데이터(예: 캘린더 액세스)에 액세스해야 하는 경우 위에서 설명한 커스텀 매개변수로 처리해야 합니다. IdP는 continue_on URL을 반환하여 권한을 요청합니다.

fields가 빈 배열인 경우 요청은 다음과 같습니다.

let { token } = await navigator.credentials.get({
  identity: {
    providers: [{
      fields: [],
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      params: {
        scope: 'drive.readonly calendar.readonly',
      }
    },
  }
  mediation: 'optional',
});

fields가 빈 배열이면 사용자 에이전트는 공개 UI를 건너뜁니다.

위젯 모드에서 공개 메시지가 표시되지 않습니다. 버튼 흐름에서는 공개 UI를 완전히 건너뜁니다.
위젯 모드에서 공개 메시지가 표시되지 않습니다. 버튼 흐름에서는 공개 UI를 완전히 건너뜁니다.

계정 엔드포인트의 응답에 approved_clients의 RP와 일치하는 클라이언트 ID가 포함되지 않은 경우에도 마찬가지입니다.

이 경우 ID 어설션 엔드포인트로 전송된 disclosure_text_shown는 HTTP 본문에서 false입니다.

POST /id_assertion_endpoint HTTP/1.1
Host: idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=false

여러 configURL

여러 configURL을 사용하면 잘 알려진 파일accounts_endpointlogin_url를 구성 파일과 동일하게 지정하여 IdP에서 IdP의 여러 구성 파일을 수용할 수 있습니다.

accounts_endpointlogin_url가 잘 알려진 파일에 추가되면 IdP가 여러 구성 파일을 지원할 수 있도록 provider_urls은 무시됩니다. 그렇지 않은 경우 provider_urls이 계속 적용되어 이전 버전과 호환됩니다.

여러 configURL을 지원하는 잘 알려진 파일은 다음과 같습니다.

{
  "provider_urls": [ "https://idp.example/fedcm.json" ],
  "accounts_endpoint": "https://idp.example/accounts",
  "login_url": "https://idp.example/login"
}

이를 통해 다음을 수행할 수 있습니다.

  1. 기존의 잘 알려진 파일 및 이미 배포된 초기 버전의 브라우저와의 호환성을 유지합니다.
  2. 임의의 수의 구성 파일이 있어야 합니다(모두 동일한 accounts_endpointlogin_url를 가리키는 경우).
  3. 엔트로피가 '.well-known' 수준에서 지정되어야 하므로 accounts_endpoint에 대한 인증된 가져오기 요청에 엔트로피가 추가될 가능성이 없습니다.

여러 configURL을 지원하는 것은 선택사항이며 기존 FedCM 구현은 동일하게 유지할 수 있습니다.

맞춤 계정 라벨

맞춤 계정 라벨을 사용하면 FedCM IdP가 계정에 주석을 달 수 있으므로 RP가 구성 파일에 라벨을 지정하여 계정을 필터링할 수 있습니다. Domain Hint APILogin Hint API를 사용하면 navigator.credentials.get() 호출에 도메인을 지정하여 유사한 필터링이 가능했지만 맞춤 계정 라벨은 구성 파일을 지정하여 사용자를 필터링할 수 있습니다. 이는 여러 configURL이 사용되는 경우에 특히 유용합니다. 또한 커스텀 계정 라벨은 로그인 또는 도메인 힌트와 같은 RP가 아닌 IdP 서버에서 제공된다는 점에서도 다릅니다.

예시

IdP는 소비자용 configURL과 기업용 configURL을 각각 지원합니다. 소비자 구성 파일에는 'consumer' 라벨이 있고 엔터프라이즈 구성 파일에는 'enterprise' 라벨이 있습니다.

이러한 설정으로 잘 알려진 파일에는 여러 configURL을 허용하는 accounts_endpointlogin_url가 포함됩니다.

{
  "provider_urls": [ "https://idp.example/fedcm.json" ],
  "accounts_endpoint": "https://idp.example/accounts",
  "login_url": "https://idp.example/login"
}

accounts_endpoint가 잘 알려진 파일에 제공되면 provider_urls는 무시됩니다. RP는 navigator.credentials.get() 호출의 각 구성 파일을 직접 가리킬 수 있습니다.

소비자 구성 파일은 https://idp.example/fedcm.json에 있으며, 여기에는 include를 사용하여 'consumer'를 지정하는 accounts 속성이 포함되어 있습니다.

{
  "accounts_endpoint": "https://idp.example/accounts",
  "client_metadata_endpoint": "/client_metadata",
  "login_url": "https://idp.example/login",
  "id_assertion_endpoint": "/assertion",
  "accounts": {
    "include": "consumer"
  }
}

엔터프라이즈 구성 파일은 https://idp.example/enterprise/fedcm.json에 있으며, 여기에는 include를 사용하여 'enterprise'를 지정하는 accounts 속성이 포함되어 있습니다.

{
  "accounts_endpoint": "https://idp.example/accounts",
  "client_metadata_endpoint": "/enterprise/client_metadata",
  "login_url": "https://idp.example/login",
  "id_assertion_endpoint": "/assertion",
  "accounts": {
    "include": "enterprise"
  }
}

일반 IdP 계정 엔드포인트(이 예시의 https://idp.example/accounts)는 각 계정의 배열에 labels가 할당된 라벨 속성이 포함된 계정 목록을 반환합니다. 다음은 계정이 두 개인 사용자에 대한 응답 예입니다. 하나는 소비자용이고 다른 하나는 엔터프라이즈용입니다.

{
 "accounts": [{
   "id": "123",
   "given_name": "John",
   "name": "John Doe",
   "email": "john_doe@idp.example",
   "picture": "https://idp.example/profile/123",
   "labels": ["consumer"]
  }], [{
   "id": "4567",
   "given_name": "Jane",
   "name": "Jane Doe",
   "email": "jane_doe@idp.example",
   "picture": "https://idp.example/profile/4567",
   "labels": ["enterprise"]
  }]
}

RP가 'enterprise' 사용자의 로그인을 허용하려는 경우 navigator.credentials.get() 호출에 'enterprise' configURL 'https://idp.example/enterprise/fedcm.json'을 지정할 수 있습니다.

let { token } = await navigator.credentials.get({
  identity: {
    providers: [{
      clientId: '1234',
      nonce: '234234',
      configURL: 'https://idp.example/enterprise/fedcm.json',
    },
  }
});

따라서 사용자는 '4567'의 계정 ID만 사용하여 로그인할 수 있습니다. '123'의 계정 ID는 브라우저에서 자동으로 숨겨지므로 사용자에게 이 사이트의 IdP가 지원하지 않는 계정이 제공되지 않습니다.

오리진 트라이얼: Storage Access API의 신뢰 신호로서 FedCM

Chrome 126에서 Storage Access API의 신뢰 신호로 FedCM의 오리진 트라이얼이 시작됩니다. 이 변경사항으로 인해 FedCM을 통한 이전 권한 부여가 Storage Access API의 저장소 액세스 요청을 자동으로 승인하는 유효한 이유가 됩니다.

이는 삽입된 iframe이 맞춤설정된 리소스에 액세스하려고 할 때 유용합니다. 예를 들어 idp.example이 rp.example에 삽입되어 있고 맞춤설정된 리소스를 표시해야 하는 경우입니다. 브라우저가 서드 파티 쿠키에 대한 액세스를 제한하면 사용자가 FedCM으로 idp.example을 사용하여 rp.example에 로그인하더라도 요청에 서드 파티 쿠키가 포함되지 않으므로 삽입된 idp.example iframe에서 맞춤설정된 리소스를 요청할 수 없습니다.

이렇게 하려면 idp.example은 웹사이트에 삽입된 iframe을 통해 저장소 액세스 권한을 가져와야 하며 이 권한은 권한 메시지를 통해서만 얻을 수 있습니다.

FedCM을 Storage Access API의 신뢰 신호로 사용하면 Storage Access API 권한 검사가 저장소 액세스 프롬프트에서 제공하는 권한 부여뿐만 아니라 FedCM 프롬프트에서 부여한 권한 부여도 허용합니다.

// In top-level rp.example:

// Ensure FedCM permission has been granted.
const cred = await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: 'https://idp.example/fedcm.json',
      clientId: '123',
    }],
  },
  mediation: 'optional',
});

// In an embedded IdP iframe:

// No user gesture is needed to call this, and the call will be auto-granted.
await document.requestStorageAccess();

// This returns `true`.
const hasAccess = await document.hasStorageAccess();

사용자가 FedCM으로 로그인하면 FedCM 인증이 활성 상태인 동안 권한이 자동으로 부여됩니다. 즉, 사용자 연결이 끊어지면 권한을 요청하면 메시지가 표시됩니다.

오리진 트라이얼 참여

Chrome 126 이상에서 Chrome 플래그 chrome://flags#fedcm-authz를 사용 설정하여 FedCM Continuation API 번들을 로컬에서 사용해 볼 수 있습니다. Chrome 126 이상에서 #fedcm-with-storage-access-api를 사용 설정하여 로컬에서 Storage Access API의 신뢰 신호로 FedCM을 사용해 볼 수도 있습니다.

이 기능은 오리진 트라이얼로도 제공됩니다. 오리진 트라이얼을 통해 새로운 기능을 사용해 보고 사용성, 실용성, 효과에 관한 의견을 제공할 수 있습니다. 자세한 내용은 오리진 트라이얼 시작하기를 참고하세요.

FedCM Continuation API 번들 오리진 트라이얼을 사용해 보려면 2개의 오리진 트라이얼 토큰을 만듭니다.

버튼 흐름과 함께 Continuation API를 사용 설정하려면 버튼 모드 API 오리진 체험판도 사용 설정하세요.

FedCM을 Storage Access API 오리진 트라이얼의 신뢰 신호로 사용해 보려면 다음 안내를 따르세요.

Storage Access API 오리진 트라이얼의 신뢰 신호로서의 Continuation API 번들 오리진 트라이얼과 FedCM은 Chrome 126부터 사용할 수 있습니다.

RP에 서드 파티 오리진 트라이얼 등록

  1. 오리진 트라이얼 등록 페이지로 이동합니다.
  2. 등록 버튼을 클릭하고 토큰을 요청하는 양식을 작성합니다.
  3. IdP의 원본을 웹 출처로 입력합니다.
  4. 서드 파티 일치를 확인하여 다른 출처에 JavaScript로 토큰을 삽입하세요.
  5. 제출을 클릭합니다.
  6. 발급된 토큰을 서드 파티 웹사이트에 삽입합니다.

서드 파티 웹사이트에 토큰을 삽입하려면 IdP의 출처에서 제공되는 IdP의 JavaScript 라이브러리 또는 SDK에 다음 코드를 추가합니다.

const tokenElement = document.createElement('meta');
tokenElement.httpEquiv = 'origin-trial';
tokenElement.content = 'TOKEN_GOES_HERE';
document.head.appendChild(tokenElement);

TOKEN_GOES_HERE를 자체 토큰으로 바꿉니다.