question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

400 Bad Request when trying to authenticate

See original GitHub issue

Hi, does this method still work? I seem to hit 400 Bad Request whenever I try to authenticate the user. I know the authenticate logic works because it works fine when a token is returned using the username/password flow, just not with oauth.

Is this related to?

Starting November 9th, 2020 end users will no longer be able to grant consent to newly registered multitenant apps without verified publishers.

Code if needed: It’s ruby, but the flow is the same, just trying to port it for my ruby app.


      def oauth2_token_request()
        client_id = ''
        client_secret = ''

        params = {
          client_id: client_id,
          response_type: 'code',
          approval_prompt: 'auto',
          scope: DEFAULT_SCOPES.join(' '),
          redirect_uri: 'http://localhost:3000/my_auth/xbox'
        }

        url = "https://login.live.com/oauth20_authorize.srf?#{ URI.encode_www_form(params) }"

        puts url
        puts 'Please input your code: '
        code = gets.strip

        request = self.class.post("https://login.live.com/oauth20_token.srf",
          body: {
            grant_type: 'authorization_code',
            code: code,
            client_id: client_id,
            client_secret: client_secret,
            scope: DEFAULT_SCOPES.join(' '),
            redirect_uri: 'http://localhost:3000/my_auth/xbox'
          }
        ).parsed_response

        user_auth = {
          token_type: request['token_type'],
          expires_in: (Time.now + (request['expires_in'] || 0)),
          scope: request['scope'],
          access_token: request['access_token'],
          refresh_token: request['refresh_token'],
          user_id: request['user_id'],
          issued_at: DateTime.now.to_s
        }
        puts request
        authenticate(request['access_token'])
      end

      def authenticate(access_token)
        body = {
          'RelyingParty' => 'http://auth.xboxlive.com',
          'TokenType' => 'JWT',
          'Properties' => {
            'AuthMethod' => 'RPS',
            'SiteName' => 'user.auth.xboxlive.com',
            'RpsTicket' => "d=#{ access_token }"
          }
        }
        headers = {
          'x-xbl-contract-version' => '1'
        }

        url = 'https://user.auth.xboxlive.com/user/authenticate'
        request = self.class.post(url, body: body, headers: headers, debug_output: $stdout)

        binding.pry
        token = request['Token']
        uhs = request.dig('DisplayClaims', 'xui', 0, 'uhs')

        return token, uhs
      end

I’ve already tried: https://gist.github.com/tuxuser/8b7cc153cdecd0a9c3f2694850fa90bd with no luck.

Here’s the request:

https://login.live.com/oauth20_authorize.srf?client_id=[]&response_type=code&approval_prompt=auto&scope=Xboxlive.signin+Xboxlive.offline_access&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fmy_auth%2Fxbox
Please input your code:
  M.R3_BAY.e034920f-6dc5-5bc3-1852-0a2919f8f30b
{"token_type"=>"bearer", "expires_in"=>3600, "scope"=>"XboxLive.signin XboxLive.offline_access", "access_token"=>"EwA4A+pvBAAUKods63Ys1fGlwiccIFJ+qE1hANsAAbiIYjDJky2QL6/X8P7OGIRcd05TeP/im5rzQYoxgWeMpL5SoB73O2uE73b2O3WrPx6Jf2Bbtur8YiZwncnlzFkSIn9atIPWYyGNYLWBDW+QMUQ0sguxVfJv+TOo2UVxeEy4zYI3l+ytp1yGgVeki3SnOtTs9t7yYvMd/euHQOfZNy8JniOkyRDd5VFpg8bRNmPbInLAcyKWE0xyuLeR04hFResTxDb+GEqRRtBIXZ+AoqhdTZnJQxYDIDnYmtwdjMUpO5yA/P4KJeKMwyr3m8HtG0qz8A9ZTFrMGUfSrhBQx9kc5EhZwGMYsScSe2XmYZ9jPTrx/5TQHxnGdPFwjmUDZgAACEK4c+VYuIKBCAJyLPFlAstkoFupkGIZvHRKYjq7x3gYBTdoUoF0GauH5D2o44ri8XZriAT8emvneWiqPQwS67mCD3e8lWgoJ1IiQ0hzwybRvRbeKvtQyMx4M6l+AWqqLnJleIQkPw8BPKWALBwTlok5o8RXPcc9fbW0KBJ6gZuzzvRGTSXUCVsqC1mRA5rXRTPJmbl7M2p8Up2d/WMYGWbr82kx8NeLKc6aftPWpyK/6blAH1bAWySvrL1kHjWPjC/7P0VGSqVW8NdzYOn2qBo2EXt6ZhYeCa6EW21r8mXy8zt8WTlNIKWcumI+D3yh+eglFmfkTwtl7ZqZPBoAHatXFk1XeQ3ab4OPAdrpgbUvalxe2eA+sexYMnld5SzlfYCWVow6mzIHCl1cc2LxpaEpFZqgbnw8Y+bM1zBx1kUZtiJQSRZ/6U6TTzvl5LEh0wmhPm6RewiKrae9NRFebO1+3vh4my/SunzbYXkW6MzH1TCGceGY8QWIXpLutoLSoVr6MlM7ROaIaVe73jWM9w7YL3tsd6i9doDk+oofuQ8TK+w9QQgQ5cHaW+HJ+HV784R8a6dEiLTRmzbRZdbeUIpwozea/hiBDuhysRWBh6M3oLvHXDCvj2igAblOdyYRS7pfPKAb2nng9ViX5BWQqLcunRg8k9EaQqyB84WYlWhNvcvGMTHBB0L5XyimZ8NKaDy+LQI=", "refresh_token"=>"M.R3_BAY.CayW3LvCUOqPgkjJFVyGtQ534sq11ocTJaYWEf3nacddh14dHhtrrzOTiizFQaVQhli6hfZ6Qdq5hgHm04cFcFvvOahxpNznRCu9artf6EE1*s86KDv0kT9tSg0WhkV8pRmPgmvUjemNDPqxueZEfqifMoQZOcwy9se46sG4nX2uK3d4HJo1lA4jCeXTMXV5mT3uuL!YFLHWOLyB1k7CZKvjNUrlaEA0s0lc7xVoSrSfSHOo9331s9s84mWVrioDmoQa8KdPVc1eiYnc!BFz8J5SZq!T1Kn3dVYRFj7wkIDLILx!MbsjaSEMvwbXO3BfvRo4ViOBXCkXX!jaQ9j6a2plEg7fMFMga2Nl27IazvcKlod1oRMS78zaTXPMx2ilInaTZV7354*qpKiQqXwDVJ4$", "user_id"=>""}
opening connection to user.auth.xboxlive.com:443...
  opened
starting SSL for user.auth.xboxlive.com:443...
  SSL established, protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384
<- "POST /user/authenticate HTTP/1.1\r\nX-Xbl-Contract-Version: 1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: user.auth.xboxlive.com\r\nContent-Length: 1329\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n"
<- "RelyingParty=http%3A%2F%2Fauth.xboxlive.com&TokenType=JWT&Properties%5BAuthMethod%5D=RPS&Properties%5BSiteName%5D=user.auth.xboxlive.com&Properties%5BRpsTicket%5D=d%3DEwA4A%2BpvBAAUKods63Ys1fGlwiccIFJ%2BqE1hANsAAbiIYjDJky2QL6%2FX8P7OGIRcd05TeP%2Fim5rzQYoxgWeMpL5SoB73O2uE73b2O3WrPx6Jf2Bbtur8YiZwncnlzFkSIn9atIPWYyGNYLWBDW%2BQMUQ0sguxVfJv%2BTOo2UVxeEy4zYI3l%2Bytp1yGgVeki3SnOtTs9t7yYvMd%2FeuHQOfZNy8JniOkyRDd5VFpg8bRNmPbInLAcyKWE0xyuLeR04hFResTxDb%2BGEqRRtBIXZ%2BAoqhdTZnJQxYDIDnYmtwdjMUpO5yA%2FP4KJeKMwyr3m8HtG0qz8A9ZTFrMGUfSrhBQx9kc5EhZwGMYsScSe2XmYZ9jPTrx%2F5TQHxnGdPFwjmUDZgAACEK4c%2BVYuIKBCAJyLPFlAstkoFupkGIZvHRKYjq7x3gYBTdoUoF0GauH5D2o44ri8XZriAT8emvneWiqPQwS67mCD3e8lWgoJ1IiQ0hzwybRvRbeKvtQyMx4M6l%2BAWqqLnJleIQkPw8BPKWALBwTlok5o8RXPcc9fbW0KBJ6gZuzzvRGTSXUCVsqC1mRA5rXRTPJmbl7M2p8Up2d%2FWMYGWbr82kx8NeLKc6aftPWpyK%2F6blAH1bAWySvrL1kHjWPjC%2F7P0VGSqVW8NdzYOn2qBo2EXt6ZhYeCa6EW21r8mXy8zt8WTlNIKWcumI%2BD3yh%2BeglFmfkTwtl7ZqZPBoAHatXFk1XeQ3ab4OPAdrpgbUvalxe2eA%2BsexYMnld5SzlfYCWVow6mzIHCl1cc2LxpaEpFZqgbnw8Y%2BbM1zBx1kUZtiJQSRZ%2F6U6TTzvl5LEh0wmhPm6RewiKrae9NRFebO1%2B3vh4my%2FSunzbYXkW6MzH1TCGceGY8QWIXpLutoLSoVr6MlM7ROaIaVe73jWM9w7YL3tsd6i9doDk%2BoofuQ8TK%2Bw9QQgQ5cHaW%2BHJ%2BHV784R8a6dEiLTRmzbRZdbeUIpwozea%2FhiBDuhysRWBh6M3oLvHXDCvj2igAblOdyYRS7pfPKAb2nng9ViX5BWQqLcunRg8k9EaQqyB84WYlWhNvcvGMTHBB0L5XyimZ8NKaDy%2BLQI%3D"
-> "HTTP/1.1 400 Bad Request\r\n"
-> "Cache-Control: no-cache, no-store\r\n"
-> "Content-Length: 0\r\n"
-> "MS-CV: G45KgNf/vEiFoy4qfpYJFA.0\r\n"
-> "X-Content-Type-Options: nosniff\r\n"
-> "X-XblCorrelationId: 00000000-0000-0000-0000-000000000000\r\n"
-> "Date: Thu, 14 Jan 2021 10:08:09 GMT\r\n"
-> "Connection: close\r\n"
-> "\r\n"
reading 0 bytes...
  -> ""
read 0 bytes
Conn close

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7

github_iconTop GitHub Comments

1reaction
pacMakavelicommented, Jan 14, 2021

I could’ve sworn that this was my first ‘fix’ I tried when I was getting this issue. Remember to send JSON, kids!

        headers = {
          'Content-Type' => 'application/json',
          'x-xbl-contract-version' => '1'
        }
0reactions
pacMakavelicommented, Apr 29, 2021

Sure did! I’m not going to post the gem I’m currently using because of personal reasons, but this is the full relevant piece of code which should get you up and running.

require 'httparty'

module XBOX
  module Oauth
    class Client
      include HTTParty

      DEFAULT_SCOPES ||= ['XboxLive.signin', 'XboxLive.offline_access'].join(' ').freeze

      USER_AGENT ||= [
        'Mozilla/5.0 (games.directory/2.0; XboxLiveAuth/3.0)',
        'AppleWebKit/537.36 (KHTML, like Gecko)',
        'Chrome/71.0.3578.98 Safari/537.36'
      ].join(' ').freeze

      CLIENTS ||= {
        MY_XBOX_LIVE: '0000000048093EE3',
        XBOX_APP: '000000004C12AE6F'
      }.freeze

      def self.authorization_url
        url = self.new.oauth_authorize_url

        if XBOX::Oauth.configuration.debug
          puts "Follow this link '#{ url }' and input the code returned below."
          puts 'Code: '
          code = gets.rstrip

          # Start the Authentication flow
          #
          self.new.authenticate(code)
        end

        url
      end

      def initialize
        raise 'Please read the README.md on how to configure the XBOX::Oauth module.' unless XBOX::Oauth.valid?
      end

      def authenticate(code, refresh: false)

        # Start the Authentication flow
        #
        access_token, refresh_token = request_oauth_token(code, refresh: refresh)
        user_token = get_user_token(access_token)
        session = get_xsts_token(user_token)

        # Return a new Session containing all the required information to start communicating with XBOX Live API
        #
        XBOX::Oauth::Session.new(session, access_token, refresh_token)
      end

      def refresh(refresh_token)
        authenticate(refresh_token, refresh: true)
      end

      # TODO: Add a way for the User to request the app be removed from their allowed oauth services
      #
      def delete(refresh_toke)
        # self.class.delete()
      end

      ### Authorize the account for the app in order to request an authorization code.
      #
      # Redirect the client to Microsoft' website where he will be prompted for login details.
      # If the Azure app has been configured correctly, on successful login, Microsoft will redirect back to the app using
      # the @redirect_uri configuration value along with a code which has to be passed to @oauth20_token
      #
      # @return Encoded URL to be used in redirecting the client
      # @example https://login.live.com/oauth20_authorize.srf?client_id=client_id&response_type=code&approval_prompt=auto&scope=Xboxlive.signin+Xboxlive.offline_access&redirect_uri=redirect_uri
      #
      def oauth_authorize_url
        params = {
          client_id: XBOX::Oauth.configuration.client_id,
          response_type: 'code',
          approval_prompt: 'auto',
          scope: DEFAULT_SCOPES,
          redirect_uri: XBOX::Oauth.configuration.redirect_uri
        }

        "https://login.live.com/oauth20_authorize.srf?#{ URI.encode_www_form(params) }"
      end

      ## Authenticate the account via the authorization code returned by @oauth_authorize_url and receive an access and
      # refresh token
      #
      # @return [Hash] containing the access_token, refresh_token, expiration_date, etc..
      # @example
      #
      def request_oauth_token(code, refresh: false)
        raise '"code" is empty; you need it silly! Did you forget to launch @authorization_url?' unless code

        body = {
          grant_type: (refresh ? 'refresh_token' : 'authorization_code'),
          client_id: XBOX::Oauth.configuration.client_id,
          scope: DEFAULT_SCOPES,
          redirect_uri: XBOX::Oauth.configuration.redirect_uri,
        }

        body[refresh ? 'refresh_token' : 'code'] = code
        body[:client_secret] = client_secret unless (client_secret = XBOX::Oauth.configuration.client_secret)

        request = self.class.post('https://login.live.com/oauth20_token.srf',
          body: body
        ).parsed_response

        raise request['error_description'] if request.has_key?('error')

        return request['access_token'], request['refresh_token']
      end

      # Authenticate with XBOX Live using the user's access_token returned by @request_oauth_token and receive a
      # user_token and uhs id which are to be used with @get_xsts_token
      #
      # @return
      # @example
      #
      def get_user_token(access_token)
        raise '"access_token" is empty; you need it silly!' unless access_token

        request = self.class.post('https://user.auth.xboxlive.com/user/authenticate',
          body: {
            'RelyingParty' => 'http://auth.xboxlive.com',
            'TokenType' => 'JWT',
            'Properties' => {
              'AuthMethod' => 'RPS',
              'SiteName' => 'user.auth.xboxlive.com',
              'RpsTicket' => "d=#{ access_token }"
            }
          }.to_json,

          headers: {
            'Content-Type' => 'application/json',
            'x-xbl-contract-version' => '1'
          }
        )

        request.parsed_response['Token']
      end

      # Authorize via user token and receive final X token
      #
      # @return [Hash]
      #
      def get_xsts_token(user_tokens = [])
        raise '"user_tokens" is empty; you need it silly!' if user_tokens.empty?

        request = self.class.post('https://xsts.auth.xboxlive.com/xsts/authorize',
          body: {
            'RelyingParty' => 'http://xboxlive.com',
            'TokenType' => 'JWT',
            'Properties' => {
              'UserTokens' => [user_tokens],
              # 'DeviceToken' => '',
              # 'TitleToken' => '',
              # 'OptionalDisplayClaims' => [''],
              'SandboxId' => 'RETAIL'
            }
          }.to_json,

          headers: {
            'Content-Type' => 'application/json',
            'x-xbl-contract-version' => '1'
          }
        )

        raise 'An error occured in get_xsts_token' if request.code != 200

        request.parsed_response
      end
    end
  end
end

And this is how I use it in my app


# Placeholder for the XBOX Authentication service
# REVIEW: Create an omniauth-xbox gem wrapper for xbox-oauth and let omniauth deal with this
#
class MyAuthController < ApplicationController
  def xbox
    if (code = params[:code])
      request = XBOX::Oauth::Client.new.authenticate(code)
      user = User.find_for_oauth(request, 'xbox', current_user)

      if user
        sign_in(user, event: :authentication)

        # Quick hack for allowing users to login with XBOX Live; No point in trying to figure
        # out a nicer way since all this will be handled by omniauth.
        #
        redirect_to user_url(current_user), fallback_location: root_url
      end
    else
      redirect_to XBOX::Oauth::Client.authorization_url
    end
  end
end
Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Fix a 400 Bad Request Error [Causes and Fixes]
Quick and Easy Ways to Fix a 400 Bad Request Error · Force Refresh the Page · Check the Requested URL · Test...
Read more >
Error 400 Bad Request authentication - Auth0 Community
Returning 400 means that the request was malformed. In other words, the data stream sent by the client to the server didn't follow...
Read more >
400 Bad Request - HTTP - MDN Web Docs
The HyperText Transfer Protocol (HTTP) 400 Bad Request response status code indicates that the server cannot or will not process the request ......
Read more >
How to Fix a 400 Bad Request Error: 8 Easy Methods
Most HTTP error 400 bad requests are caused by malformed request syntax, invalid request message framing, or deceptive request routing.
Read more >
400 Bad Request Error When Trying To Authenticate ...
Some users have a browser error page displayed when they try to authenticate using OAM. The page error is "400 Bad Request". The...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found