Auth Web APIs

介绍如何使用Web API完成Epic Games身份验证流程

阅读时间11分钟

Epic 游戏服务(Epic Games Services)使用OAuth 2.0协议进行身份验证和授权,它支持常见的 web 服务器和客户端应用用例。此外,Epic 还针对一些特殊用例引入了自定义授权类型。

在开始之前,你需要从 Epic 获取 OAuth 2.0 客户端凭证。凭证会以客户端 ID 和密钥的形式提供,你从 Epic 授权服务器请求访问令牌时会用到它们。更多详情请参阅Epic 账号服务入门中的使用指南。

场景

Epic Games 商店中的游戏客户端

Epic Games 商店 启动的游戏客户端会使用一次性 交换码 通过 Epic 授权服务器进行身份验证。该交换码由 Epic 启动程序 生成,作为命令行参数传递到 游戏客户端

游戏客户端启动后,会向 Epic 令牌端点发出请求,请求包中的信息包括客户端凭证和交换代码。响应包的内容包括 访问令牌刷新令牌(可选) 以及完成身份验证的客户端和账号的相关信息。

游戏客户端随后对 Epic 服务发出的所有请求都将包含该访问令牌。访问令牌还可传递至受信任的游戏服务器用于验证,或者用于服务到服务请求。

适用情况下,令牌响应中还可包含刷新令牌。访问令牌到期(一般为 2 小时)后,游戏客户端将需要使用刷新令牌。这通常会在访问令牌签发后的 2 小时内发生。

EGS客户端身份验证流程

展示 Epic Games 启动程序身份验证流程的图表。点击查看大图。

Web 服务器应用程序

对于服务器端应用程序,该流程首先引导用户在 Web 浏览器上完成 Epic 授权流程来获取 授权代码。系统将要求用户使用其 Epic Games 账号登录,并可能要求用户授权应用程序。授权完成后,用户代理将以授权代码作为查询参数,重定向回你的 Web 应用程序。

重定向之后,Web 服务器将向 Epic 令牌端点发出请求,包括客户端凭证和授权代码。响应将包括访问令牌以及完成身份验证的客户端和账号的相关信息。

Web 服务器随后对 Epic 服务发出的所有请求都将包含该访问令牌。

身份验证

作为验证流程中的第一步,用户必须使用 Epic 服务进行身份验证。我们仅支持使用OAuth 2.0进行身份验证,以及自定义授权类型。

当客户端获得了请求令牌所需的信息(包括交换代码、授权代码、用户凭证等)后,它会首先请求获取访问令牌。

请求访问令牌

要请求访问令牌,客户端将向 Epic 令牌端点发出 HTTP 请求,同时传递客户端凭证(客户端 ID 和密钥)和用户凭证。

Epic 令牌端点地址为 https://api.epicgames.dev/epic/oauth/v1/token 。如果你想表面不再需要访问令牌,请使用 https://api.epicgames.dev/epic/oauth/v1/revoke。该端点实现了RFC 7009 - OAuth 2.0 Token Revocation

客户端凭证将使用基本授权模式在 Authorization 标头(header)中传递。此端点支持下列 post 参数:

参数名称 说明
grant_type 使用的授权类型:exchange_codepasswordrefresh_tokenclient_credentials
deployment_id 客户端试图用于身份验证的部署 ID。此参数会影响与其他需要部署的服务的交互。如果不是公共部署,则只有授权用户才能登录。 如果部署未公开,则只有授权用户才能登录。有关部署和部署 ID 的更多信息,请参阅产品、沙盒和部署ID。 注意:你必须使用该唯一标识符来使用电子商务API(Ecommerce API)以及请求游戏客户端使用的访问令牌。
scope 用户请求的(权限)范围,以空格分隔。例如:basic profilefriends_listpresence
对于 password 授权类型
注意: password 授权类型不适用于启用2FA的情况。
username 账户的用户名(电子邮件地址);仅与 password 授权类型一起使用。
password 账户密码;仅与 password 授权类型一起使用。
对于 exchange_code 授权类型
exchange_code 启动器传递到游戏客户端的交换代码;仅用于 exchange_code 授权类型。
对于 authorization_code 授权类型
code 从授权服务器中获取的授权代码。
对于 client_credentials 授权类型(参见网络授权
client_id 你的应用的OAuth客户端ID。
client_secret 你的应用的OAuth客户端密钥。

这些参数应包含在请求体中。查询参数将被忽略。

以下片段展示了一段简单的请求示例(使用 密码 授权类型):

POST /epic/oauth/v1/token HTTP/1.1
Host: api.epicgames.dev
Content-Type: application/x-www-form-urlencoded
Authorization: Basic Zm9vOmJhcg==
grant_type=password&
deployment_id=foo&
scope=basic_profile friends_list presence&
username=user@example.com&
password=s3cr3t

响应包含以下字段:

响应说明
access_token访问令牌,可以有一个前缀(例如:eg1~token)。在 Epic 服务请求中,应使用 Bearer 类型在 Authorization 标头中按原样传递此值。
expires_in令牌过期之前的秒数。
expires_atISO 8601 格式的到期日期。
account_id令牌目标用户的 Epic 账号 ID。
client_id用于生成此令牌的客户端 ID。
application_id与客户端关联的应用程序 ID。
token_type令牌类型,该值将始终为 bearer 类型。
refresh_token刷新令牌,根据客户端配置返回的可选项。此刷新令牌可用于在访问令牌到期之前或之后延长会话。
refresh_expires刷新令牌到期前的秒数。
refresh_expires_atISO 8601 格式的刷新令牌到期时间。

以下片段展示了一段简单的响应示例:

{
"scope": "basic_profile friends_list presence",
"token_type": "bearer",
"access_token": "eyJ0IjoiZXBpY19pZCIsImFsZyI6IlJTMjU2Iiwia2lkIjoibldVQzlxSFVldWRHcnBXb3FvVXVHZkFIYmVWM2NsRnlsdFRYMzhFbXJKSSJ9.eyJhdWQiOiJ4eXphNzg5MWxoeE1WWUdDT043TGduS1paOEhRR0Q1SCIsInN1YiI6Ijk2MjZmNDQxMDU1MzQ5Y2U4Y2I3ZDdkNWE0ODNlYWEyIiwidCI6ImVwaWNfaWQiLCJzY29wZSI6ImJhc2ljX3Byb2ZpbGUgZnJpZW5kc19saXN0IHByZXNlbmNlIiwiYXBwaWQiOiJmZ2hpNDU2N08wM0hST3hFandibjdrZ1hwQmhuaFd3diIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZXBpY2dhbWVzLmRldlwvZXBpY1wvb2F1dGhcL3YxIiwiZG4iOiJLcm5icnkiLCJleHAiOjE1ODgyODYwODMsImlhdCI6MTU4ODI3ODg4Mywibm9uY2UiOiJuLUI1cGNsSXZaSkJaQU1KTDVsNkdvUnJDTzNiRT0iLCJqdGkiOiI2NGMzMGQwMjk4YTM0MzdjOGE3NGU1OTAxYzM0ODZiNSJ9.MZRoCRpjIb--dD7hxoo2GvjSPhUSNpOq1FhtShTBmzMJ1qlHFPzNaUiAEETAc3mabGPKyOxUP6Q1FBadr_P_UtbtB7kf34hN2VTv5czW6WOx1HdpjwUQZuxFyDc_aix7FCS0Egu4rZlC65b-B0FUVlial_s_FrH8ou5L_d-4I0KVpIwtv-b_M6EQ9jtLdQRfMaP6aV0rIerrbqFZ617Pe7XT4IO9jZFwM8F5aDTeDHkkOO41wyVibrm38799lP4B65RIv9CwbAL-TVmV1L5gFYITaZhi5ShfZzTvxAk-3Dxwp8c5JvcO68zpbya5gFSAfhsd7vt9YLU0gQR2uXq3Vw",
"refresh_token": "eyJ0IjoiZXBpY19pZCIsImFsZyI6IlJTMjU2Iiwia2lkIjoibldVQzlxSFVldWRHcnBXb3FvVXVHZkFIYmVWM2NsRnlsdFRYMzhFbXJKSSJ9.eyJhdWQiOiJ4eXphNzg5MWxoeE1WWUdDT043TGduS1paOEhRR0Q1SCIsInN1YiI6Ijk2MjZmNDQxMDU1MzQ5Y2U4Y2I3ZDdkNWE0ODNlYWEyIiwidCI6ImVwaWNfaWQiLCJhcHBpZCI6ImZnaGk0NTY3TzAzSFJPeEVqd2JuN2tnWHBCaG5oV3d2Iiwic2NvcGUiOiJiYXNpY19wcm9maWxlIGZyaWVuZHNfbGlzdCBwcmVzZW5jZSIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZXBpY2dhbWVzLmRldlwvZXBpY1wvb2F1dGhcL3YxIiwiZG4iOiJLcm5icnkiLCJleHAiOjE1ODgzMDc2ODMsImlhdCI6MTU4ODI3ODg4MywianRpIjoiYzczYjA2NmUyZDU4NGVkNTk0NjZiOThiNzI3NzJiMjAifQ.O-eVa46NimubKwxe9SwlHxciivu0XWe1-DSL74mMiA_PpPoW0yKL9DfmsLxiPCwsRB5_hQTc6_FM7G1FyfKtX_VVAp90MZPkhCbAbfKmTpQVcL0Ya6kve4KMG8KxeLVfLLhubCbJTYlnDNVHobbpvpQtHd8Ys321ZNDJj05l_tnZzdgus-xmCO6orX4UP4wDd1jAOXXeqRT47OXuLCgSE0q6Osfh-ENPwh6ph1i7ld759xPV0oNcQb8XiPxnT6_FUmFugzG1YS1z9bTnVWmbP2RmYluue5VQm5EKGJZ91Alve8s2eNEtDfUqaBLZ45pqGkc1KjbYTtP0a_1ue2BpkQ",
"expires_in": 7200,
"expires_at": "2020-04-30T22:34:43.549Z",
"refresh_expires_in": 28800,
"refresh_expires_at": "2020-05-01T04:34:43.549Z",
"account_id": "9626f441055349ce8cb7d7d5a483eaa2",
"client_id"