next-auth icon indicating copy to clipboard operation
next-auth copied to clipboard

Using Azure DevOps APIs

Open nawok opened this issue 2 years ago β€’ 2 comments

Question πŸ’¬

Hello everyone!

I am trying to implement a Next.js tool to work with Azure DevOps APIs. I am following the documentation from Microsoft on Authorize access to REST APIs with OAuth 2.0.

I was able to send the authorization request for my app with required scopes and can see my app in my Azure DevOps account.

// pages/api/auth/[...nextauth].ts

import { NextApiRequest, NextApiResponse } from "next"
import NextAuth from "next-auth"
import invariant from "tiny-invariant"

const clientId = process.env.AZURE_DEVOPS_APP_ID
const clientSecret = process.env.AZURE_DEVOPS_CLIENT_SECRET
const scope = process.env.AZURE_DEVOPS_SCOPE
// const callbackUrl = "https://localhost/api/auth/callback/azure-devops"

invariant(clientId && clientSecret && scope)

export default (req: NextApiRequest, res: NextApiResponse) => {
  // console.log("\n=================== REQUEST ===================\n\n", { req })
  // console.log("\n=================== RESPONSE ===================\n\n", { res })
  return NextAuth(req, res, {
    providers: [
      {
        id: "azure-devops",
        name: "Azure DevOps",
        type: "oauth",
        authorization: {
          url: "https://app.vssps.visualstudio.com/oauth2/authorize",
          params: {
            scope,
            response_type: "Assertion",
          },
        },
        token: "https://app.vssps.visualstudio.com/oauth2/token",
        userinfo: "https://app.vsaex.visualstudio.com/me",
        profile: (profile) => {
          console.log(profile)
          return {
            id: "id1",
            name: "test",
            email: "[email protected]",
            image: "https://image.com/1.jpg",
          }
        },
        clientId,
        clientSecret,
      },
    ],
  })
}

But unfortunately immediately after that I get an error:

  • https://localhost/api/auth/signin?error=OAuthCallback in the URL
  • Try signing in with a different account. in the UI
  • And OAUTH_CALLBACK_ERROR + CALLBACK_OAUTH_ERROR in the log:
https://localhost/api/auth/callback/azure-devops
[next-auth][error][OAUTH_CALLBACK_ERROR] 
https://next-auth.js.org/errors#oauth_callback_error expected 200 OK, got: 400 Bad Request {
  error: {
    message: 'expected 200 OK, got: 400 Bad Request',
    stack: 'OPError: expected 200 OK, got: 400 Bad Request\n' +
      '    at processResponse (D:\\develop\\webapps\\next-auth\\node_modules\\openid-client\\lib\\helpers\\process_response.js:41:11)\n' +   
      '    at Client.grant (D:\\develop\\webapps\\next-auth\\node_modules\\openid-client\\lib\\client.js:1347:22)\n' +
      '    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n' +
      '    at async Client.oauthCallback (D:\\develop\\webapps\\next-auth\\node_modules\\openid-client\\lib\\client.js:612:24)\n' +
      '    at async oAuthCallback (D:\\develop\\webapps\\next-auth\\node_modules\\next-auth\\core\\lib\\oauth\\callback.js:115:16)\n' +      
      '    at async Object.callback (D:\\develop\\webapps\\next-auth\\node_modules\\next-auth\\core\\routes\\callback.js:50:11)\n' +
      '    at async NextAuthHandler (D:\\develop\\webapps\\next-auth\\node_modules\\next-auth\\core\\index.js:139:28)\n' +
      '    at async NextAuthNextHandler (D:\\develop\\webapps\\next-auth\\node_modules\\next-auth\\next\\index.js:21:19)\n' +
      '    at async Object.apiResolver (D:\\develop\\webapps\\next-auth\\node_modules\\next\\dist\\server\\api-utils\\node.js:185:9)\n' +    
      '    at async DevServer.runApi (D:\\develop\\webapps\\next-auth\\node_modules\\next\\dist\\server\\next-server.js:395:9)',
    name: 'OPError'
  },
  providerId: 'azure-devops',
  message: 'expected 200 OK, got: 400 Bad Request'
}
[next-auth][error][CALLBACK_OAUTH_ERROR] 
https://next-auth.js.org/errors#callback_oauth_error expected 200 OK, got: 400 Bad Request OPError: expected 200 OK, got: 400 Bad Request
    at processResponse (D:\develop\webapps\next-auth\node_modules\openid-client\lib\helpers\process_response.js:41:11)
    at Client.grant (D:\develop\webapps\next-auth\node_modules\openid-client\lib\client.js:1347:22)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Client.oauthCallback (D:\develop\webapps\next-auth\node_modules\openid-client\lib\client.js:612:24)
    at async oAuthCallback (D:\develop\webapps\next-auth\node_modules\next-auth\core\lib\oauth\callback.js:115:16)
    at async Object.callback (D:\develop\webapps\next-auth\node_modules\next-auth\core\routes\callback.js:50:11)
    at async NextAuthHandler (D:\develop\webapps\next-auth\node_modules\next-auth\core\index.js:139:28)
    at async NextAuthNextHandler (D:\develop\webapps\next-auth\node_modules\next-auth\next\index.js:21:19)
    at async Object.apiResolver (D:\develop\webapps\next-auth\node_modules\next\dist\server\api-utils\node.js:185:9)
    at async DevServer.runApi (D:\develop\webapps\next-auth\node_modules\next\dist\server\next-server.js:395:9) {
  name: 'OAuthCallbackError',
  code: undefined
}

As I understood from the FAQ I need to modify my request for the token (here is an example in C#).

Q: I get an HTTP 400 error when I try to get an access token. What might be wrong? A: Check that you set the content type to application/x-www-form-urlencoded in your request header.

How do I achieve that with NextAuth: where is my point of the override?

How to reproduce β˜•οΈ

  • Clone https://github.com/nawok/next-auth-azure-devops
  • Enable HTTPS for localhost:
    • This is a requirement for Azure DevOps
    • Inspect certificates/install.ps1 for a possible solution (replace choco with brew on Macs)
    • Run yarn ssl to start a local proxy with a self-signed cert
  • Register your app in DevOps as described in app-setup.md
  • Set the environment variables

Contributing πŸ™ŒπŸ½

Yes, I would like to help with the provider when I figure out the details.

nawok avatar Jun 08 '22 12:06 nawok

All right, some hours later I got unstuck by implementing makeTokenRequest(context) found here.

I will close this issue when I get to the finish line: I still need to implement the token rotation according to the guide. Don’t want to spam the issue tracker with new questions on the same topic. πŸ™‚

nawok avatar Jun 08 '22 23:06 nawok

It looks like this issue did not receive any activity for 60 days. It will be closed in 7 days if no further activity occurs. If you think your issue is still relevant, commenting will keep it open. Thanks!

stale[bot] avatar Aug 10 '22 02:08 stale[bot]

The complete implementation with docs is provided in PR #4698 and is waiting for the review.

nawok avatar Aug 11 '22 22:08 nawok