사용자 API 키 클라이언트가 키 생성을 위해 유효한 auth_redirect를 등록할 수 있도록 하는 것이 실현 가능한지 고려하고 있습니다.
현재 기능
현재 사용자 API 키 리디렉션은 호스트 사이트에서 사이트 설정 allowed_user_api_auth_redirects를 통해 등록해야 합니다. 키 생성 요청과 함께 전송되는 모든 auth_redirect는 해당 사이트 설정 목록과 대조되어 검증됩니다(여기 참조). 이는 오픈 리디렉션(다양한 보안 위험을 초래할 수 있음)을 방지하는 합리적인 보호 조치입니다.
동인(Efficient Cause)
이러한 고찰의 동인은 ActivityPub 플러그인의 사용자 인증 기능입니다. 이 기능은 사용자가 ActivityPub 액터의 소유권을 증명하여 해당 액터의 활동이 특정 인스턴스에서 사용자의 계정과 연관되도록 합니다. 그 모습은 다음과 같습니다.
현재 이는 모든 Mastodon 서버가 OAuth 클라이언트의 프로그래매틱 생성을 허용하는 OAuth 제공자이므로 Mastodon과 함께 작동합니다. 플로우의 작동 방식은 다음과 같습니다:
사용자는 자신의 계정이 있는 Mastodon 도메인을 식별합니다.
해당 도메인에서 처음 인증하는 경우, 플러그인은 그 Mastodon 서버에서 OAuth 앱을 생성하고, 리디렉션을 등록하며, OAuth 플로우를 위한 클라이언트 자격 증명을 얻습니다.
플러그인은 2단계에서 생성한(또는 이전에 생성한) OAuth 앱을 사용하여 사용자와 OAuth 플로우를 수행합니다.
목표는 User Api Keys를 사용하여 Discourse에서 실질적으로 동일한 기능을 갖게 하는 것입니다. 이는 이미 이 PR에서 구현되었습니다.
이 플로우에는 호스트 사이트가 클라이언트의 도메인 또는 리디렉션을 allowed_user_api_auth_redirects에 이미 추가해 두어야 합니다.
가능한 변경 사항
현재 제가 생각하고 있는 것은 discourse/discourse에 다음과 같은 내용을 수행하는 PR을 만드는 것입니다.
user_api_key_client 테이블 생성
컬럼:
user_api_key에서 이관된 client_id 및 application_name
redirect_uri (선택 사항)
public_key (선택 사항)
client_id와 application_name을 사용하는 기존 모든 기능은 user_api_key_client를 통해 이전과 동일하게 작동할 것입니다.
클라이언트 등록 루트 추가
post "/user-api-key/register" => "user_api_keys#register"
필수 매개변수:
application_name
client_id
public_key
auth_redirect
액션:
매개변수를 검증하고 user_api_key_client에 저장
성공 시 성공 코드를 반환
생성 작업에서 등록된 클라이언트 사용 허용
UserApiKeyController의 create 액션을 다음과 같이 변경합니다.
client_id가 user_api_key_client에 존재하고 auth_redirect와 public_key를 모두 가진 경우:
전반적으로 이 안을 지지합니다. ActivityPub 플러그인 및 그 이상의 범위에서 사용자 인증 워크플로를 마찰 없이 활성화할 수 있기 때문입니다.
다만 몇 가지 질문이 있습니다:
마이그레이션 방식에는 크게 찬성하지 않습니다. 개별 사용자 키의 ID와 이름은 등록된 클라이언트의 ID와 이름과 독립적이기 때문에, 기존 사용자 API 키를 그대로 유지하는 것이 더 좋다고 생각합니다. 대신 user_api_key에 user_api_key_client_id 컬럼을 추가하는 방식을 고려해 볼 수 있습니다. 그러면 클라이언트가 연관된 키는 클라이언트에서 설정된 리다이렉트를 사용할 수 있고, 기존 키는 물론 현재 동작 방식을 유지하게 됩니다.
현재 user_api_keys 테이블은 아마도 두 개의 별도 데이터 모델이어야 할 것, 즉 사용자 API 키와 사용자 API 키 클라이언트를 혼재시키고 있습니다. 현재 방식의 한계를 키 생성 메서드(여기)에서 볼 수 있습니다:
# destroy any old keys we had
UserApiKey.where(user_id: current_user.id, client_id: params[:client_id]).destroy_all
key =
UserApiKey.create!(
application_name: @application_name,
client_id: params[:client_id],
user_id: current_user.id,
push_url: params[:push_url],
scopes: scopes.map { |name| UserApiKeyScope.new(name: name) },
)
새로운 키를 생성하려면 client_id가 유일하게 유지되도록 동일한 client_id를 가진 모든 키를 삭제해야 합니다.换句话说, 현재 데이터 모델은 클라이언트와 키 사이의 1:1 관계를 요구합니다. 이 1:1 관계는 일부 사용 사례에는 유용하지만 다른 사용 사례에는 제한이 됩니다.
실제로 이 1:1 제한이 여러분이 제안한 방식이 작동하지 않을 가능성이 높은 이유입니다.
클라이언트가 여러 키에 대해 리다이렉트를 등록하려면 client_id의 유일성이 키 자체에서 독립적이어야 합니다. 그렇지 않으면 client_id가 등록 작업에서 리다이렉트를 식별하는 데 사용되므로 여러 키에 대한 등록이 작동하지 않습니다.
client_id와 application_name을 전용 user_api_key_clients 테이블로 이동하면 1:1 케이스를 유지하면서 1:N 케이스도 허용할 수 있으며, ActivityPub 목적의 redirect_uri 등록과 같은 기능이 가능해집니다.
말씀하시는 뜻을 이해합니다. 하지만 기존 client_id를 마이그레이션하면, 마이그레이션된 ID/이름이 1:1 클라이언트에 해당하는 키들이기 때문에 새 테이블에서도 이러한 혼합이 일부 유지될 것입니다. 특히 향후 관리자 관점에서, 다대일(multi-to-one) 클라이언트의 목록을 가지고 있는 것이 좋습니다.