Trouble generating (or identifying) the correct token for file upload
I've gone around and around on this and I suspect I'm missing something simple. I'm lost in a maze of StackOverflow, Google, and Box Community searches and my head is spinning.
I'm trying to upload a file to box.com by generating an admin token and client and trying to impersonate another user. If I don't impersonate the user, I receive a permission denied error, which I understand to be because admins cannot manipulate content. If I do impersonate the user, I receive the "Cannot obtain user token based on the enterprise configuration for your app" error message
My code for setting up the tokens & users is:
var boxJWT = new BoxJWTAuth(BoxConfig.CreateFromJsonString(jsonConfig)); _userId = "users_email_address"; var adminToken = boxJWT.AdminToken(); var adminClient = boxJWT.AdminClient(_userId, adminToken); var userToken = boxJWT.UserToken(_userId);
It conks out on the creating the userToken.
The upload code that I have works but only as long as I use the "bearer" method with a developer key, but once I try to switch to an API key things don't work.
var client = new RestClient("https://upload.box.com/api/2.0"); var request = new RestRequest("files/content", Method.POST);
const string folderId = "12345"; const string apiKey = "..."; string Headers = string.Format("BoxAuth api_key={0}&auth_token={1}", apiKey, userToken); request.AddHeader("Authorization", Headers); request.AddParameter("parent_id", folderId); byte[] byteArray = System.IO.File.ReadAllBytes(path); request.AddFile("filename", byteArray, "dave-send-fixed.txt"); var responses = client.Execute(request); var content = responses.Content;
How do I bolt these two pieces together and get a working upload?
Is it possible to get the correct token (either admin or user) from this setup and pass along as the BoxAuth parameter? And/or how do I resolve the permissions error above?
Thanks
-
Hey ,
You'll have a better shot getting this answered on the Box Developer Forum. Perhaps , could move the thread there.
Bob
-
Thanks. I reposted at https://community.box.com/t5/Box-Developer-Forum/Trouble-generating-or-identifying-the-correct-token-for-file/m-p/52988#M4253/
Feel free to lock, close, or delete this thread.
-
By default, apps do not have permission to generate tokens for arbitrary users. You'll need to ensure that the app has the "Generate User Access Tokens" feature toggled on in the Configuration tab in the Box Developer Console:
Noe that changing this setting will also require the enterprise admin to reauthorize your app in any enterprises it is being used in.
-
Thanks!
That setting is certainly on in my profile. I'll try reauthorizing the permissions, but I'm pretty sure I've done that.
Two quick follow on questions:
1) Is my logic/code otherwise correct? (assuming the need for reauthorization does the trick)?
2) I have "perform actions as users" enabled. Is that ok/correct?
-
I can't really speak to the correctness of your code by sight-reading it — you'll have to run it and see. The "Perform Actions As Users" feature allows an admin or service account to impersonate other users by setting the "As-User" header. If you're not using that header, you shouldn't need that setting to be turned on.
Also, it looks like you're writing all of this in C# — is there something that prevented you from using the Box .NET SDK? My team maintains that SDK, so if it's lacking some necessary functionality we would love to know! The SDK should handle operations like file upload for you, so you don't need to worry about writing it all yourself.
-
I really appreciate the insight.
the code compiles and runs...but returns an error. If the line about generating the user token by id (email) is correct then I'm comfortable chasing down permissions errors in the portal. I've just been all over the place with code and errors that its getting confusing.
As for the sdk, I am using it for the adminToken but tried to switch out so that i could more easily troubleshoot the process in a synchronous environment because it's an asp.net web application. I had that code working perfectly with a bearer token and then when I switched away to the auth keys things went sideways so i was trying to at least use part of what I knew was working to troubleshoot the entire thing because the async calls were causing issues. If you happen to have an asp.net forms sample, I'll gladly dissect they to see if I can make my code work.
Thanks again. It's much appreciated.
-
I'm not sure if this is what you meant, but the user ID is NOT the user's email address. It's their numeric ID — see the id file of the user object for more information. One way you can get this ID by searching the users in the enterprise for the one with the email address you already know (using the filter_term parameter of that API endpoint).
-
Ok, that was certainly part of the problem! Putting in the correct UserID eliminated the initial error.
But now I'm seeing the following:{"error":"invalid_grant","error_description":"Please check the 'sub' claim. The 'sub' specified is invalid."}
Shouldn't that claim be automatically asserted when the AsUser parameter is defined when creating the AdminClient?
-
The `sub` claim in the JWT should always be a Box ID — depending on the value of `box_sub_type` it would be either the ID of the user you're trying to generate tokens for, or the ID of the enterprise you're authenticating as the service account for. There's an API guide on manually constructing JWT claims that has more information for you, in case you haven't seen it. What sort of value are you currently using for `sub` and `box_sub_type`?
-
Well, I tried to forget everything I've read and tried in the past few days and was just working through the sample code at https://github.com/box/box-windows-sdk-v2 trying to use just the libraries from nuget without manually constructing anything hoping that I could get this to work.
If I just do the following, I get an error.
var jsonConfig = System.IO.File.ReadAllText( "C:\\Users\\Dave\\Documents\\Visual Studio 2015\\Projects\\BoxTest\\BoxTest\\box.json"); var boxConfig = BoxConfig.CreateFromJsonString(jsonConfig); var boxJwt = new BoxJWTAuth(boxConfig); // Authenticate var adminToken = boxJwt.AdminToken(); //valid for 60 minutes so should be cached and re-used var adminClient = boxJwt.AdminClient(adminToken); //get a user client var userToken = boxJwt.UserToken(UserId); //valid for 60 minutes so should be cached and re-used var userClient = boxJwt.UserClient(userToken, UserId);
In this case shouldn't specifying the UserID automatically add the correct claims for JWT?
The error is:
{"error":"invalid_grant","error_description":"Please check the 'sub' claim. The 'sub' specified is invalid."}
-
Definitely, the SDK should be making the request correctly. I looked at the SDK code, and it basically just takes whatever string you pass it for the user ID and puts that in the sub claim. What is the actual value of UserId in this case? It should generally look like a string of digits, e.g. "12345678".
-
Per fiddler request (body)
grant_type: urn:ietf:params:oauth:grant-type:jwt-bearer
and raw response:
HTTP/1.1 400 Bad Request
Date: Tue, 13 Mar 2018 23:41:29 GMT
Content-Type: application/json
Content-Length: 109
Cache-Control: no-store
Strict-Transport-Security: max-age=31536000
Set-Cookie: box_visitor_id=5aa861a75e9cd0.81480970; expires=Wed, 13-Mar-2019 23:41:29 GMT; Max-Age=31536000; path=/; domain=.box.com; secure
Set-Cookie: bv=OPS-42232; expires=Tue, 20-Mar-2018 23:41:29 GMT; Max-Age=604800; path=/; domain=.app.box.com; secure
Set-Cookie: cn=0; expires=Wed, 13-Mar-2019 23:41:29 GMT; Max-Age=31536000; path=/; domain=.app.box.com; secure
Set-Cookie: site_preference=desktop; path=/; domain=.box.com; secure
Age: 2
Connection: keep-alive{"error":"invalid_grant","error_description":"Please check the 'sub' claim. The 'sub' specified is invalid."}
-
Since your ID looks valid, I suspect this might be an issue with the actual user you're trying to generate tokens for. Can you verify the following for me?
1) The user ID is actually correct and points to the user you expect it to
2) That user is either an app user or a managed user in your enterprise
The second one is pretty important — the user MUST belong to the enterprise that authorized your app, and cannot be a free user or personal account not associated with the enterprise.
Please sign in to leave a comment.
Comments
14 comments