身份验证网络API

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

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小时内发生。

展示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。

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

参数名称

说明

grant_type

使用的授权类型:exchange_codepasswordrefresh_tokenclient_credentials

deployment_id

客户端试图用于身份验证的部署ID。此参数会影响与其他需要部署的服务的交互。如果不是公共部署,则只有授权用户才能登录。

scope

用户请求的范围(权限)列表,以空格分隔。例如:basic profile friends_list presence

对于 password 授权类型

username

账号用户名(电子邮件地址),仅用于 密码 授权类型。

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_at

ISO 8601格式的到期日期。

account_id

令牌目标用户的Epic账号ID。

client_id

用于生成此令牌的客户端ID。

application_id

与客户端关联的应用程序ID。

token_id

令牌类型,该值将始终为 bearer 类型。

refresh_token

刷新令牌,根据客户端配置返回的可选项。此刷新令牌可用于在访问令牌到期之前或之后延长会话。

refresh_expires

刷新令牌到期前的秒数。

refresh_expires_at

ISO 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": "xyza7891lhxMVYGCON7LgnKZZ8HQGD5H",
  "application_id": "fghi4567O03HROxEjwbn7kgXpBhnhWwv"
}

访问令牌应始终按 Authorization 头文件中的原样传递给Epic服务。例如:Authorization: Bearer eyJraWQiOiJ0RkM...

Web应用程序

对于Web应用程序和服务器端应用程序,在请求访问令牌之前需要获得授权代码。使用Web授权之前,你的Epic OAuth客户端必须配置一个重定向URL。

要启动该流程,应用程序需将用户重定向到授权页面,该页面将要求用户登录Epic Games账号。授权URL为:

https://www.epicgames.com/id/authorize?client_id={client_id}&response_type=code&scope=basic_profile

你可以使用额外参数 redirect_uri={redirect_uri} 来定义多个重定向URL。如果多于一条重定向,验证URL是:

https://www.epicgames.com/id/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&scope=basic_profile

用户登录后,将使用授权代码返回到已配置的重定向URL。你的应用程序应该使用该代码获取访问令牌,并使用请求访问令牌中所述的 authorization_code 授权类型。

我们还支持可选的状态参数,该参数可维持请求与回调之间的状态,用于防止跨站点请求伪造攻击

以下是用户身份验证后的重定向示例:

https://www.example.com/?code=cfd1de1a8d224203b0445fe977838d81&state=rfGWJux2WL86Zxr6nKApCAnDo8KexEUE

验证访问令牌

离线验证

访问令牌是一个 JWT (JSON 网络令牌),其中包括用于验证令牌真实性的标头和签名。

验证签名前,需要从我们的服务中获取以JSON Web密钥(JWK)形式发布的 公共密钥。我们使用JWK集合格式(包括当前所有公共密钥)公开单个端点。虽然密钥集不会频繁更改,但随时可能轮换使用密钥。

JWK端点地址为 https://api.epicgames.dev/epic/oauth/v1/.well-known/jwks.json

建议已获取公共密钥的客户端将密钥缓存一段合理时间。虽然密钥会轮换使用,但对于给定的密钥ID,其密钥不会更改。

以下片段展示了从公共密钥端点返回的响应示例:

{"keys":[{"kty":"RSA","e":"AQAB","kid":"WMS7EnkIGpcH9DGZsv2WcY9xsuFnZCtxZjj4Ahb-_8E","n":"l6XI48ujknQQlsJgpGXg4l2i_DuUxuG2GXTzkOG7UtX4MqkVBCfW1t1JIIc8q0kCInC2oBwhC599ZCmd-cOi0kS7Aquv68fjERIRK9oCUnF_lJg296jV8xcalFY0FOWX--qX3xGKL33VjJBMIrIu7ETjj06s-v4li22CnHmu2lDkrp_FPTVzFscn-XRIojqIFb7pKRFPt27m12FNE_Rd9bqlVCkvMNuE7VTpTOrSfKk5B01M5IuXKXk0pTAWnelqaD9bHjAExe2I_183lp_uFhNN4hLTjOojxl-dK8Jy2OCPEAsg5rs9Lwttp3zZ--y0sM7UttN2dE0w3F2f352MNQ"}]}

在线验证

如果无法选择离线验证,可以使用有效的访问令牌来调用令牌信息端点,进行在线验证。此端点实现了令牌内省规范。

此令牌信息端点地址为 https://api.epicgames.dev/epic/oauth/v1/tokenInfo

下列片段展示了用于验证令牌的请求示例:

POST /epic/oauth/v1/tokenInfo HTTP/1.1
Host: api.epicgames.dev
Content-Type: application/x-www-form-urlencoded
token=eyJ0IjoiZXBpY19pZCIsImFsZyI6IlJTMjU2Iiwia2lkIjoibldVQzlxSFVldWRHcnBXb3FvVXVHZkFIYmVWM2NsRnlsdFRYMzhFbXJKSSJ9.eyJhdWQiOiJ4eXphNzg5MWxoeE1WWUdDT043TGduS1paOEhRR0Q1SCIsInN1YiI6Ijk2MjZmNDQxMDU1MzQ5Y2U4Y2I3ZDdkNWE0ODNlYWEyIiwidCI6ImVwaWNfaWQiLCJzY29wZSI6ImJhc2ljX3Byb2ZpbGUgZnJpZW5kc19saXN0IHByZXNlbmNlIiwiYXBwaWQiOiJmZ2hpNDU2N08wM0hST3hFandibjdrZ1hwQmhuaFd3diIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZXBpY2dhbWVzLmRldlwvZXBpY1wvb2F1dGhcL3YxIiwiZG4iOiJLcm5icnkiLCJleHAiOjE1ODgyODYwODMsImlhdCI6MTU4ODI3ODg4Mywibm9uY2UiOiJuLUI1cGNsSXZaSkJaQU1KTDVsNkdvUnJDTzNiRT0iLCJqdGkiOiI2NGMzMGQwMjk4YTM0MzdjOGE3NGU1OTAxYzM0ODZiNSJ9.MZRoCRpjIb--dD7hxoo2GvjSPhUSNpOq1FhtShTBmzMJ1qlHFPzNaUiAEETAc3mabGPKyOxUP6Q1FBadr_P_UtbtB7kf34hN2VTv5czW6WOx1HdpjwUQZuxFyDc_aix7FCS0Egu4rZlC65b-B0FUVlial_s_FrH8ou5L_d-4I0KVpIwtv-b_M6EQ9jtLdQRfMaP6aV0rIerrbqFZ617Pe7XT4IO9jZFwM8F5aDTeDHkkOO41wyVibrm38799lP4B65RIv9CwbAL-TVmV1L5gFYITaZhi5ShfZzTvxAk-3Dxwp8c5JvcO68zpbya5gFSAfhsd7vt9YLU0gQR2uXq3Vw

以下片段展示了令牌信息端点的响应示例:

{
  "active": true,
  "scope": "basic_profile friends_list presence",
  "token_type": "bearer",
  "expires_in": 6761,
  "expires_at": "2020-04-30T22:34:43.549Z",
  "account_id": "9626f441055349ce8cb7d7d5a483eaa2",
  "client_id": "xyza7891lhxMVYGCON7LgnKZZ8HQGD5H",
  "application_id": "fghi4567O03HROxEjwbn7kgXpBhnhWwv"
}

访问令牌和刷新令牌都可以使用此端点进行验证。

Epic Games商店中的游戏客户端

当你使用某个通过Epic Games商城连接的游戏客户端时,游戏客户端必须使用 exchange_code 授权类型来获取访问令牌,并传递其客户端凭证以及从启动器传递而来的代码。

在开发期间,你还可以使用 密码 授权类型,以便游戏客户端根据Epic服务进行身份验证,从而无需集成启动器。

当Epic Games启动程序启动游戏时,将传递以下命令行参数:

参数

说明

AUTH_LOGIN

不用于交换代码。

AUTH_PASSWORD

游戏客户端将使用的凭证。其中包括要传递到身份验证服务器的交换代码。

epicapp

内部应用程序名称。

epicenv

启动时环境(始终是 Prod)。

epicusername

在启动器中经过身份验证的账号的显示名称。

epicusername

在启动器中经过身份验证的账号的Epic账号ID。

epiclocale

基于用户偏好或系统语言的首选区域设置。

epicovt

包含所有权验证令牌信息的文件的完整路径。

以下是启动器传递命令行参数的示例:

-AUTH_LOGIN=unused -AUTH_PASSWORD=ed642dfd4e6f47bf8354caf1bcab2fc2 -AUTH_TYPE=exchangecode -epicapp=[AppName] -epicenv=Prod -epicusername="DisplayName" -epicuserid=ab1f86d911d74f4aa8399849e9ca9aa5 -epiclocale=en-US
-epicovt="C:/AppName/.egstore/ab1f86d911d74f4aa8399849e9ca9aa5/File.ovt"

账号信息

一旦拥有了访问令牌,你就能够代表用户向Epic服务发出请求。例如,你可以请求获取显示名称,或者用户好友的显示名称。

从访问令牌

你可以直接从访问令牌获取用户的一些相关信息。令牌被编码为 JSON Web令牌(JWT) 格式,它的头文件包含令牌类型和签名信息、一个有效负载(其中包含用户、客户端和会话的相关信息)以及一个签名。我们建议使用库来进行JWT的解码操作,如果无法使用库,请参考JWT规范。

该有效负载将包括以下信息:

声明

类型

说明

iss

字符串

发布令牌的Epic Games身份验证服务器的基本URI。

sub

字符串

使用client_credentials授权类型时,不会出现此声明。

aud

字符串

授权请求中指定的客户端ID。

iat

整型

令牌发布时间,UNIX时间戳格式。

exp

整型

令牌过期时间,UNIX时间戳格式。

jti

字符串

此令牌的唯一标识符。

t

字符串

令牌类型。此类型应始终为epic_id。该字符串将替代EG1令牌使用的版本前缀。

scope

字符串

授权给用户的范围列表,以空格分隔。

dn

字符串

用户的显示名称。

appid

字符串

授权请求中指定的应用程序ID。

pfpid

字符串

令牌请求中指定的用于部署的产品ID。

pfsid

字符串

令牌请求中指定的用于部署的沙盒ID。

pfdid

字符串

令牌请求中指定的部署ID。

我们可以使用前面例子中的令牌对有效负载进行解码,检查其是否包含以下内容:

{
  "aud": "xyza7891lhxMVYGCON7LgnKZZ8HQGD5H",
  "sub": "9626f441055349ce8cb7d7d5a483eaa2",
  "t": "epic_id",
  "scope": "basic_profile friends_list presence",
  "appid": "fghi4567O03HROxEjwbn7kgXpBhnhWwv",
  "iss": "https://api.epicgames.dev/epic/oauth/v1",
  "dn": "Krnbry",
  "exp": 1588286083,
  "iat": 1588278883,
  "nonce": "n-B5pclIvZJBZAMJL5l6GoRrCO3bE=",
  "jti": "64c30d0298a3437c8a74e5901c3486b5"
}

获取账号

除了访问令牌中的信息之外,还可以请求已登录账号的类似信息,或任何与你的应用程序交互的其他账号的类似信息。

出于隐私方面的考虑,你只能请求之前已同意使用你的应用程序的那些用户的账号信息。

账号信息端点地址为 https://api.epicgames.dev/epic/id/v1/accounts。调用此端点时,你需要为正在尝试解析的账号指定一个或多个accountId查询参数。单个请求最多允许包含 50 个账号。

下列片段展示了获取多个账号信息的请求示例:

GET /epic/id/v1/accounts?accountId=foo531f86d911d74f4aa8399849e9ca9ba6&accountId=barcbab941052f540c69fbd92ddc3bf9027 HTTP/1.1
Host: api.epicgames.dev
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer [token]eyJ0IjoiZXBpY19pZCIsImFsZyI6IlJTMjU2Iiwia2lkIjoibldVQzlxSFVldWRHcnBXb3FvVXVHZkFIYmVWM2NsRnlsdFRYMzhFbXJKSSJ9.eyJhdWQiOiJ4eXphNzg5MWxoeE1WWUdDT043TGduS1paOEhRR0Q1SCIsInN1YiI6Ijk2MjZmNDQxMDU1MzQ5Y2U4Y2I3ZDdkNWE0ODNlYWEyIiwidCI6ImVwaWNfaWQiLCJzY29wZSI6ImJhc2ljX3Byb2ZpbGUgZnJpZW5kc19saXN0IHByZXNlbmNlIiwiYXBwaWQiOiJmZ2hpNDU2N08wM0hST3hFandibjdrZ1hwQmhuaFd3diIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZXBpY2dhbWVzLmRldlwvZXBpY1wvb2F1dGhcL3YxIiwiZG4iOiJLcm5icnkiLCJleHAiOjE1ODgyODYwODMsImlhdCI6MTU4ODI3ODg4Mywibm9uY2UiOiJuLUI1cGNsSXZaSkJaQU1KTDVsNkdvUnJDTzNiRT0iLCJqdGkiOiI2NGMzMGQwMjk4YTM0MzdjOGE3NGU1OTAxYzM0ODZiNSJ9.MZRoCRpjIb--dD7hxoo2GvjSPhUSNpOq1FhtShTBmzMJ1qlHFPzNaUiAEETAc3mabGPKyOxUP6Q1FBadr_P_UtbtB7kf34hN2VTv5czW6WOx1HdpjwUQZuxFyDc_aix7FCS0Egu4rZlC65b-B0FUVlial_s_FrH8ou5L_d-4I0KVpIwtv-b_M6EQ9jtLdQRfMaP6aV0rIerrbqFZ617Pe7XT4IO9jZFwM8F5aDTeDHkkOO41wyVibrm38799lP4B65RIv9CwbAL-TVmV1L5gFYITaZhi5ShfZzTvxAk-3Dxwp8c5JvcO68zpbya5gFSAfhsd7vt9YLU0gQR2uXq3Vw

以下片段是上述请求的响应示例:

[
    {
        "accountId": "531f86d911d74f4aa8399849e9ca9ba6",
        "displayName": "eas_user",
        "preferredLanguage": "en",
        "linkedAccounts": [
            {
                "identityProviderId": "xbl",
                "displayName": "eas_user_xbl"
            }
        ]
    },
    {
        "accountId": "cbab941052f540c69fbd92ddc3bf9027",
        "displayName": "other_user",
        "preferredLanguage": "en"
    }
]