nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
24.76k stars 3.49k forks source link

Custom Provider: Epic Games - Unknown Configuration Issue Leads to OAuthError #5560

Closed aceaspades-worldspark closed 2 years ago

aceaspades-worldspark commented 2 years ago

Provider type

Custom provider

Environment

System: OS: macOS 12.6 CPU: (8) x64 Apple M1 Memory: 26.22 MB / 16.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 16.14.2 - /usr/local/bin/node Yarn: 1.22.10 - ~/.npm-global/bin/yarn npm: 8.5.0 - /usr/local/bin/npm Browsers: Chrome: 106.0.5249.103 Firefox: 105.0 Safari: 15.6.1 npmPackages: next: latest => 12.3.1 next-auth: latest => 4.13.0 react: ^18.2.0 => 18.2.0

Reproduction URL

Repo: https://github.com/aceaspades-worldspark/next-auth-example Live: https://next-auth-example-mu-blush.vercel.app/api/auth/signin Callback URL (set on dev.epicgames.com): https://next-auth-example-mu-blush.vercel.app/api/auth/callback/epic

Describe the issue

When I select "Sign In With EPIC", I'm properly redirected to the Epic Games login screen. Once I'm redirected back, I'm met with "Try signing in with a different account." No logs are presented to the console, nor to my Vercel Function logs.

How to reproduce

  1. Follow this URL: https://next-auth-example-mu-blush.vercel.app/api/auth/signin
  2. Select "Sign In With EPIC"
  3. Consent to pairing with our application, Sparkadia (in development, feel free to use a dummy account)
  4. You'll be redirected to the reproduction URL, with ?error=OAuthCallback appended to the params

Expected behavior

I'd expect to be properly logged into my NextAuth application! Or, at least have something in my logs so I can better understand the issue.

balazsorban44 commented 2 years ago

The repo is private.

aceaspades-worldspark commented 2 years ago

@balazsorban44 Ah, my mistake. It is now public. I've also added a bit more information to the original issue.

balazsorban44 commented 2 years ago

Looks like you are missing the openid scope which is required for OIDC clients. I also tried to log in on the above link but got:

image

Tried creating my own client, but it does not accept localhost. :sweat:

Could you specify how you set up your client? Am I in the right place at: https://dev.epicgames.com/portal/en-US/my-org/products/my-product/settings/clients

What's the recommended flow to test this locally?

Your config can be simplified to this:

{
  id: "epic",
  name: "Epic",
  type: "oauth",
  clientId: process.env.EPIC_CLIENT_ID,
  wellKnown: "https://api.epicgames.dev/epic/oauth/v1/.well-known/openid-configuration",
  authorization: { params: { scope: "openid basic_profile" },
  profile(profile) {
    return {
      profile: profile,
      id: profile.id,
    }
  }
}
aceaspades-worldspark commented 2 years ago

@balazsorban44 Ah, your being restricted by Epic makes sense, we are still awaiting full approval for our application to go live to the public, so only dev accounts are allowed to sign up. Should be good to go by mid-week next week. But with a dev account, you'll see an OAuth application consent, then everything works pretty smooth following that.

Localhost, I was just looking into this; Epic doesn't allow localhost as a Redirect URL, and they recommended using ngrok to route localhost to a custom domain; looking into that for our dev team. Described here: https://eoshelp.epicgames.com/s/feed/0D54z00007N0hA8CAJ?language=en_US

What I've taken to doing for development is create a Vercel deployment and test from there. That's this application, the testing environment.

Correct client link, yes. Ours is set up with the provided GameClient policy type.

I'll add openid to the scope and see what happens, one moment...

aceaspades-worldspark commented 2 years ago

@balazsorban44 I've updated the config to exactly what you've provided, but I am still receiving the same error message when redirected back to my application.

aceaspades-worldspark commented 2 years ago

@balazsorban44 Here's the steps I followed to get a Client set up (after setting up an Organization account, Product, and Sandbox for our game, those instructions are available in the guide one before this one): https://dev.epicgames.com/docs/dev-portal/client-credentials

Our Client is using the default GameClient permissions.

balazsorban44 commented 2 years ago

So the client credentials is for machine-2-machine communication, you would likely need https://dev.epicgames.com/docs/web-api-ref/authentication to act on behalf of the user.

I'll try to check later on with ngrok. :+1:

aceaspades-worldspark commented 2 years ago

So the client credentials is for machine-2-machine communication, you would likely need https://dev.epicgames.com/docs/web-api-ref/authentication to act on behalf of the user.

I'll try to check later on with ngrok. 👍

I'll clarify about the Client setup; I followed the authentication instructions (https://dev.epicgames.com/docs/web-api-ref/authentication) to set up NextAuth before I opened this issue. But in order to generate a Client ID, as is required by NextAuth for the custom provider, I created an Epic Client with default GameClient permissions (permission type requires a logged in user). That process provided me with a Client ID, Client Secret, and a place to specify redirect URLs (.../api/auth/callback/epic). As stated by Epic: "Any program that needs to access Epic Online Services (EOS) functionality on behalf of a product is considered an EOS Client."

I've got ngrok working wonderfully, still getting error=OAuthSignin though. Luckuly, I'm getting error logs properly now.

I tried without clientId and clientSecret, but got message: 'client_id is required', then added clientId, and got message: 'client_secret_basic client authentication method requires a client_secret'.

So I've added clientSecret, and now the error that has probably been throwing since I originally opened the issue:

message: 'invalid_client (Sorry the client credentials you are using are invalid)'

Despite this error, I've assured that the Client ID and Secret are correct, as issued directly from Epic, and I can also assure that I do receive a code after redirect from Epic, but within milliseconds the error is thrown and the code disappears. Here's what I get back (I scrambled/changed the numbers in the code and state, but they're the same length and content)

https://MYTUNNEL.ngrok.io/api/auth/callback/epic?code=a11563474340989bca28d11b905170ef&state=JXeMSWKe6WxDkWKHZdgYS1j1q_Y6NYhkAroH8bvI7Dk

balazsorban44 commented 2 years ago

Likely need to tweak the token_endpoint_auth_method. The basic is client_secret_basic, but I did not see one in your provider config.

See the docs: https://next-auth.js.org/configuration/providers/oauth#client-option https://github.com/panva/node-openid-client/blob/main/docs/README.md#new-clientmetadata-jwks-options

More likely, you forgot to set clientSecret?

aceaspades-worldspark commented 2 years ago

Likely need to tweak the token_endpoint_auth_method. The basic is client_secret_basic, but I did not see one in your provider config.

See the docs: https://next-auth.js.org/configuration/providers/oauth#client-option https://github.com/panva/node-openid-client/blob/main/docs/README.md#new-clientmetadata-jwks-options

More likely, you forgot to set clientSecret?

Awesome, I'll give that a look.

Also, I'm definitely setting clientSecret. Here's my current code:

{
      id: "epic",
      name: "Epic",
      type: "oauth",
      clientId: process.env.EPIC_CLIENT_ID,
      clientSecret: process.env.EPIC_CLIENT_SECRET,
      wellKnown:
        "https://api.epicgames.dev/epic/oauth/v1/.well-known/openid-configuration",
      authorization: { params: { scope: "openid basic_profile" } },
      profile(profile) {
        return {
          profile: profile,
          id: profile.id,
        };
      },
    },
balazsorban44 commented 2 years ago

Your config should do it, really. I have to admit, setting up Epic for dev is time-consuming, I am stuck at: image

Which requires domain verification, etc.

aceaspades-worldspark commented 2 years ago
{
  id: "epic",
  name: "Epic",
  type: "oauth",
  clientId: process.env.EPIC_ID,
  clientSecret: process.env.EPIC_SECRET,
  wellKnown:
    "https://api.epicgames.dev/epic/oauth/v1/.well-known/openid-configuration",
  authorization: { params: { scope: "openid basic_profile" } },
  profile(profile) {
    console.log(profile)
    return {
      profile: profile,
      id: profile.id,
    }
  },
}

This should really do it. I have to admit, setting up Epic for dev is time-consuming, I am stuck at: image

Which requires domain verification, etc.

The exact response you'll get back, once everything is finished, would look like:

https://mytunnel.ngrok.io/api/auth/callback/epic?code=a11563474340989bca28d11b905170ef&state=JXeMSWKe6WxDkWKHZdgYS1j1q_Y6NYhkAroH8bvI7Dk

balazsorban44 commented 2 years ago

At this point, it's just config. You can contact me on Twitter for more help, but I would like to close this issue as this is not a NextAuth.js bug. :+1:

aceaspades-worldspark commented 1 year ago

Hoping to re-open this issue.

I've attempted to work with @balazsorban44 on Twitter to resolve this configuration issue, to no avail unfortunately, our correspondence has been very limited on the matter; I believe you are occupied otherwise, perfectly understandable. This is a timing-critical issue for my work, however, and it has now been a month since I opened this issue originally.

Since this is an unknown issue with configuring a custom provider using an OAuth-compliant authentication system (Epic Account Services), I'm going to attempt to re-open this issue so that it can be handled by any available member of the NextAuth team, during working hours.

I have successfully crafted an Axios work-around to obtain a JWT from Epic within NextJS (following their well-known), then set it as a signed HTTPOnly cookie (Keygrip + Cookies), however I do not know how to integrate this with NextAuth.

Expedient assistance would be incredibly helpful, this is for a production application built for the company I work for. I will have to abandon NextAuth completely, with a small grudge on my shoulder from the experience, if I cannot receive assistance with the issue. Thank you for your time.

OMaxOe commented 1 year ago

I had the same problem like you. I was able to solve it by requesting the token endpoint itself.

The process.env.EPIC_AUTH_TOKEN in the Authorization header is a base64 encoded string in the following format Basic <Base64(ClientId:ClientSecret)>

Hope this helps you.


    providers: [{
        id: 'epic',
        name: 'Epic',
        type: 'oauth',
        wellKnown: "https://api.epicgames.dev/epic/oauth/v1/.well-known/openid-configuration",
        authorization: {params: {scope: "openid basic_profile"}},
        token: {
            async request(context) {
                const response = await axios.post(process.env.EPIC_AUTH_TOKEN_URL, {
                    grant_type: "authorization_code",
                    code: context.params.code,
                    scope: "openid basic_profile",
                    state: context.params.state,
                }, {
                    headers: {
                        "content-type": "application/x-www-form-urlencoded",
                        "Authorization": `Basic ${process.env.EPIC_AUTH_TOKEN}`
                    }
                })

                return {tokens: response.data};
            }
        },
        clientId: process.env.EPIC_AUTH_CLIENT_ID,
        clientSecret: process.env.EPIC_AUTH_CLIENT_SECRET,
        profile: (profile) => {
           ....
        }
    }]
serhii-lypko commented 9 months ago

@OMaxOe thank you very much! While I have the same issue like @aceaspades-worldspark had, the only one work around I found so far - is what you've suggested.

simplyzetax commented 2 months ago

@OMaxOe First of all, thank you. Your method brought me much further than I got before, but I haven't been able to get it to work fully. Do you think I could contact you some other way, or you could help me here as you seem to know what you are doing. I'm currently just getting an error when being redirected to the callback with the valid code

error {
  errorCode: 'errors.com.epicgames.account.invalid_client_credentials',
  errorMessage: 'Sorry the client credentials you are using are invalid',
  messageVars: [],
  numericErrorCode: 18033,
  originatingService: 'com.epicgames.account.admin',
  intent: 'prod',
  error_description: 'Sorry the client credentials you are using are invalid',
  error: 'invalid_client'
}
[auth][error] CallbackRouteError: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: Error: TODO: Handle OAuth 2.0 response body error
    at handleOAuth (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/actions/callback/oauth/callback.js:112:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Module.callback (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/actions/callback/index.js:37:41)
    at async AuthInternal (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/index.js:39:24)
    at async Auth (webpack-internal:///(rsc)/./node_modules/@auth/core/index.js:126:34)
    at async C:\Users\finni\Desktop\lowk\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:55038
    at async ek.execute (C:\Users\finni\Desktop\lowk\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:45808)
    at async ek.handle (C:\Users\finni\Desktop\lowk\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:56292)
    at async doRender (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\base-server.js:1377:42)
    at async cacheEntry.responseCache.get.routeKind (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\base-server.js:1587:40)
    at async DevServer.renderToResponseWithComponentsImpl (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\base-server.js:1507:28)
    at async DevServer.renderPageComponent (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\base-server.js:1931:24)
    at async DevServer.renderToResponseImpl (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\base-server.js:1969:32)
    at async DevServer.pipeImpl (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\base-server.js:920:25)
    at async NextNodeServer.handleCatchallRenderRequest (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\next-server.js:272:17)
    at async DevServer.handleRequestImpl (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\base-server.js:816:17)
    at async C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\dev\next-dev-server.js:339:20
    at async Span.traceAsyncFn (C:\Users\finni\Desktop\lowk\node_modules\next\dist\trace\trace.js:154:20)
    at async DevServer.handleRequest (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\dev\next-dev-server.js:336:24)
    at async invokeRender (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\lib\router-server.js:174:21)
    at async handleRequest (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\lib\router-server.js:353:24)
    at async requestHandlerImpl (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\lib\router-server.js:377:13)
    at async Server.requestListener (C:\Users\finni\Desktop\lowk\node_modules\next\dist\server\lib\start-server.js:141:13)
[auth][details]: {
  "provider": "epic"

The client credentials I am using are definitely working, and I'm not even sure which function the error stems from, as it's not one I defined myself.

simplyzetax commented 2 months ago

image

The code is definitely being generated and returned properly, it just decides not to work for some reason