Skip to main content

I am using Golang to work with the Box API. However, I am trying to generate access tokens through the method of using JWT to eliminate the need for user interaction beyond initial setup. However, after creating a JWT and trying to send it in an oAuth request, I am failing to retrieve an access token. The following to functions create a JWT to use in an oAuth request to gain an access token. However, the response body is empty and the HTTP request generates a 400 (Bad Request) error. After the functions I show the result of printing out the resp.Status and resp.Body

// JWTAUTHURL - URL for oAUTH for Box
const JWTAUTHURL string = "https://api.box.com/oauth2/token"

// JWTGRANTTYPE - mandatory parameter for box oAuth
const JWTGRANTTYPE string = "urn:ietf:params:oauth:grant-type:jwt-bearer"

// oAuthResponse holds decoded JSON response from Box
type oAuthResponse struct {
AccessToken string `json:"access_token"`
Expires int `json:"expires_in"`
RestrictedTo []string `json:"restricted_to"`
TokenType string `json:"token_type"`
}

// CreateJWTAssertion - build up the JSON Web Token for oAuth
func CreateJWTAssertion(PublicKeyID string, ClientID string, Sub string, user *AppUserResponse) (string, error) {

var signingKey []byte
var err error
var msg, tokenString string

signingKey, err = ioutil.ReadFile("private_key.pem")

if err != nil {
msg = "Unable to read signing key. Please ensure your private signing key is in the ./keys/ directory"
return msg, err
}

// Generate JTI Value
jti, err := exec.Command("uuidgen").Output()
if err != nil {
msg = "Unable to generate JTI value"
return msg, err
}

token := jwt.New(jwt.SigningMethodHS256)
claims := make(jwt.MapClaims)
token.Header["alg"] = "HS256"
token.Header["typ"] = "JWT"
token.Header["kid"] = PublicKeyID
claims["iss"] = ClientID
claims["aud"] = JWTAUTHURL
claims["jti"] = jti
claims["exp"] = time.Now().Add(time.Second * 45).Unix()

// Create the JWT either for the enterprise or for a specific user.
if user.ID != "" {
claims["box_sub_type"] = "user"
claims["sub"] = user.ID
} else {
claims["box_sub_type"] = "enterprise"
claims["sub"] = Sub
}
token.Claims = claims

// Sign the JWT
tokenString, err = token.SignedString(signingKey)

if err != nil {
msg = "Unable to sign token, please check that you have a signing key in ./keys/"
return msg, err
}

return tokenString, err
}

// SendOAuthRequest - Sends a POST to authenticate against Box using JWT Assertion
func SendOAuthRequest(ClientID string, ClientSecret string, JWToken string) (string, error) {

var err error
var msg string
var decodedResponse *oAuthResponse

hc := http.Client{}
form := url.Values{}

// Build form to POST
form.Add("grant_type", JWTGRANTTYPE)
form.Add("client_id", ClientID)
form.Add("client_secret", ClientSecret)
form.Add("assertion", JWToken)

// Here is where the code stops working, returns an empty body
// The request looks like it should be working
req, err := http.NewRequest("POST", JWTAUTHURL, strings.NewReader(form.Encode()))
req.PostForm = form
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
if err != nil {
return msg, err
}

resp, err := hc.Do(req)
if err != nil {
msg = "Error submitting request to Box API"
return msg, err
}

//
fmt.Println(resp.Status)
fmt.Println(resp.Body)
//

err = json.NewDecoder(resp.Body).Decode(&decodedResponse)

if err != nil {
msg = "Error decoding OAuthResponse"
} else {
// We only need the Access Token
msg = decodedResponse.AccessToken
}

return msg, err
}
400 Bad Request
&{0xc420064100 {0 0} false 0x5f48b0 0x5f4840}

 


 Per the JWT authentication documentation, the Box API does not currently support the HS256 JWT signature algorithm that you're using.  Could you try changing to RS256 instead and see if that works?



 Thank you for your reply. I have changed it to RS256 and am able to successfully generate a JWT. However I am still getting the same HTTP 400 error as a bad request. I think the error may lie in my SendOAuthRequest function. Any ideas of why it could be considered a bad request?



I'm sure this is extremely late, but I'm just working through this now.


So, you're failing on the


/oauth2/token

request? I'm actually getting the token back. (My problem is that I'm getting failures when I use it.)


Why are you passing the body as a string? Create a bytes.NewReader.


Reply