I ma trying to refresh my access token using the refresh token I have but I get following exception:
com.box.boxjavalibv2.exceptions.BoxServerException:
{"error":"access_denied","error_description":"Access denied"}
Please tell me what could be wrong with my request and why I am getting access_denied
If I send invalid refresh token, then I get
Caused by: com.box.boxjavalibv2.exceptions.BoxServerException:
{"error":"invalid_grant","error_description":"Invalid refresh token"}
I want to know the reasons for access_denied.
------------------- relevant code ------------------
BoxOAuthRequestObject requestObject = BoxOAuthRequestObject.refreshOAuthRequestObject(refreshToken, clientId,
clientSecret);
try {
// Authenticate with the new token
BoxOAuthToken boxOAuthToken = client.getOAuthManager().refreshOAuth(requestObject);
Not really sure what's going on without more information of your code.
One thing is that the sdk does auto-refresh the OAuth token. So basically you don't need to refresh it yourself. Please check https://github.com/box/box-java-sdk-v2#authenticate
I've received that error when attempting to call API methods that accessed the "Manage an enterprise" methods, while my application was defined as "Read and write all files and folders".
Make sure you set the appropriate checkbox at the application level.
Related
I have implemented the chrome.identity launchWebAuthFlow to authenticate users of a web extension against an oauth2 provider and the entire flow works perfectly, I receive the access token back in the redirect URL, I extract the token using a regex and then it is valid and accepted to query the APIs.
However, I do not understand why it does not prompt anymore for credentials when I launch again the launchWebAuthFlow. Instead, it retrieves another (valid !) token in the background. Don't get me wrong, I like this, and I prefer it works in the background, but I just don't understand how. Even after clearing all cookies and local data, when I launch the launchWebAuthFlow again it just works in the background without asking for credentials...where are they stored?
Also, not sure if that helps, but my flow is the following:
extension ->oauth2 server->azure ad SSO->enter credentials->redirect to extension
So the real authentication is managed by Azure AD. However, even when I'm signed out from Microsoft, the extension keeps getting a valid auth token when the below code is triggered and without asking for credentials...so the credentials must be stored somewhere...
chrome.identity.launchWebAuthFlow(
{
url: dev.identity_url(),
interactive: true
},
function (responseWithToken) {
// the access token needs to be extracted from the response.
console.log(responseWithToken);
let token = responseWithToken.match(/(?<=access_token=).*(?=&token_type)/);
token = token[0];
chrome.storage.local.set({ "auth-token": token }, function () {
console.log(`Access Token has been saved: ${token}`);
});
}
);
I was able to connect and upload videos using the library but when I deleted the app connection on Vimeo.com (as a test) the app didn't authorize again.
the upload looks like it's working but nothing is uploaded as the app is no longer connected.
I deleted the app on the phone and restarted but it still won't re-authorize the app.
This comes up in the output:
Vimeo upload state : Executing
Vimeo upload state : Finished
Invalid http status code for download task.
And this is in OldVimeoUpload.swift: ( didn't include the actual access code!)
import Foundation
class OldVimeoUpload: VimeoUpload
{
static var VIMEO_ACCESS_TOKEN :String! // = "there's a string of numbers here"
static let sharedInstance = OldVimeoUpload(backgroundSessionIdentifier: "") { () -> String? in
return VIMEO_ACCESS_TOKEN // See README for details on how to obtain and OAuth token
}
// MARK: - Initialization
override init(backgroundSessionIdentifier: String, authTokenBlock: AuthTokenBlock)
{
super.init(backgroundSessionIdentifier: backgroundSessionIdentifier, authTokenBlock: authTokenBlock)
}
}
It looks like the access token number is commented out. I deleted the 2 forward slashes to see if that would fix it but it didn't.
I spoke too soon.
It sounds like you went to developer.vimeo.com and created an auth token. Used it to upload videos. And then went back to developer.vimeo.com and deleted the auth token.
The app / VimeoUpload will not automatically re-authenticated in this situation. You've killed the token and the app cannot request a new one for you. You'll need to create a new auth token and plug it into the app.
If this is not accurate and you're describing a different issue let us know.
If you inspect the error that's thrown from the failing request I'm guessing you'll see it's a 401 unauthorized related to using an invalid token.
Edit:
Disconnecting your app (as described in your comment below) has the same effect as deleting your auth token from developer.vimeo.com.
Also, VimeoUpload accepts a hardcoded auth token (as you see from the README and your code sample). It will not automatically re-authenticate, probably ever.
If you'd like to handle authentication in your app check out VimeoNetworking or VIMNetworking. Either of those libraries can be used to create a variety of authentication flows / scenarios. Still, if a logged in user disconnects or deletes their token, you will need them to deliberately re-authenticate (i.e. you will need to build that flow yourself). In that case, the user has explicitly stated that they don't want the app to be able to access information on their behalf. It would go against our security contract with them to automatically re-authenticate somehow.
Does that make sense?
I am using Box Api v2 (java) for integrating my webapp with Box.com.
I forward the user to the authorize url
https://www.box.com/api/oauth2/authorize?response_type=code&client_id=client-id
..and receive the 'code' at my redirect end-point. Using this code, I am able to get the access_token and refresh_token. I know that access_token is valid only for 1 hr.
But can I re-use the access_token within this 3600 sec period?
eg:a user comes back within 30 minutes and tries to fetch/put files
In this scenario, I will need to create a new BoxClient.
So what is the recommended method of client authentication using the existing access token?
If answerer can paste code snippets using the box java api, it would be quite helpful.
Or is the refreshing to get new access_token and refresh_token, the only method available?
BoxClient client = new BoxClient(MY_CLIENT_ID, MY_CLIENT_SECRET);BoxOAuthManager mgr = client.getOAuthManager();
// This is refresh
BoxOAuthRequestObject requestObject = BoxOAuthRequestObject.refreshOAuthRequestObject(REFRESH_TOKEN, MY_CLIENT_ID, MY_CLIENT_SECRET);
BoxOAuthToken newToken = mgr.refreshOAuth(requestObject);
client.authenticate(newToken);
Yes, you can re-use the access token within the 3600-second period. A common pattern for web applications is to store the access_token and refresh_token (and optionally their expiration datetimes) in a database record associated with the user.
what is the recommended method of client authentication using the existing access token?
You'll use the same authentication method as when you first acquired the access token. You don't have to do anything special to reuse it. If the access_token is expired, as determined by either an expiration timestamp comparison or 401 response, you can use the refresh_token to get a new token pair. By refreshing and persisting the token pair in this manner you can keep the user authenticated indefinitely.
BoxOAuthToken accessToken = new BoxOAuthToken(Map) will work here.
// where Map contains
{
"exprires_in":"3600",
"token_type":"bearer",
"refresh_token":"<refresh_token>",
"access_token":"<access_token>"
}
Map authMap;
BoxOAuthToken accessToken = new BoxOAuthToken(authMap);
client.authenticate(newToken);
after reading the oauth documentation on box's website, I understand the steps to get access_token and refresh_token, which requires authorization_code.
step1: send Get request to https://www.box.com/api/oauth2/authorize?response_type=code&client_id=CLIENT_ID&state=authenticated&redirect_uri=https://www.appfoo.com
step2: after entering credentials of box in browser and then click the "Allow" button, redirect to the specified redirect_uri with state=authenticated&code=AUTHORIZATION_CODE
step3: now with the AUTHORIZATION_CODE in the redirect url from step2, getting access_token can be done programmatically, by sending POST request to https://www.box.com/api/oauth2/token with AUTHORIZATION_CODE, client_id, client_secret in body and then parsing the returned json response.
My question is: is it possible to programmatically do step1 and step2 instead of via browser?
thank you very much!
The current OAuth 2 flow requires the user to go through the browser and can't be done programmatically.
It is possible, just imitate every form with cURL and on second step post cookies.
First time you will need 3 requests, next time only one (if refresh_token isn't expired, otherwise 3 again)
The point about imitating the browser transactions is a good one but instead of using cURL you would want to use a higher level tool like mechanize (available for ruby, perl and python). It will handle the cookies for you and can programatically traverse forms and links. Good for page scraping and writing scripts to order hot concert tickets from TicketMaster too!
If you have the authorization code, you then should be able to get the OAuth Token(access_token, refresh_token) via SDK, correct?
In response to aIKid, this is what I first do to get a BoxClient
BoxClient client = new BoxClient(clientId, clientSecret);
Map<String,Object> authToken = new HashMap<String,Object>();
authToken.put("exprires_in","3600");
authToken.put( "token_type","bearer");
authToken.put("refresh_token", clientRefreshToken);
authToken.put("access_token",clientAccessToken);
BoxOAuthToken oauthToken = new BoxOAuthToken(authToken);
client.authenticate(oauthToken);
return client;
Then, I have this to create a new user,
BoxUser createdUser = new BoxUser();
BoxUserRequestObject createUserRequest = BoxUserRequestObject.createEnterpriseUserRequestObject("someEmail.domain.com", "test user");
createdUser = client.getUsersManager().createEnterpriseUser(createUserRequest);
Now I'm trying to figure out how to do the RUD part of my CRUD operations on users and groups.
I've successfully installed and run the Google Drive Quick Start application called DriveCommandLine. I've also adapted it a little to GET file info for one of the files in my Drive account.
What I would like to do now is save the credentials somehow and re-use them without the user having to visit a web page each time to get an authorization code. I have checked out this page with instructions to Retrieve and Use OAuth 2.0 credentials. In order to use the example class (MyClass), I have modified the line in DriveCommandLine where the Credential object is instantiated:
Credential credential = MyClass.getCredentials(code, "");
This results in the following exception being thrown:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:187)
at com.google.api.client.json.jackson.JacksonFactory.createJsonParser(JacksonFactory.java:84)
at com.google.api.client.json.JsonFactory.fromInputStream(JsonFactory.java:247)
at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.load(GoogleClientSecrets.java:168)
at googledrive.MyClass.getFlow(MyClass.java:145)
at googledrive.MyClass.exchangeCode(MyClass.java:166)
at googledrive.MyClass.getCredentials(MyClass.java:239)
at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)
I've been looking at these APIs (Google Drive and OAuth) for 2 days now and have made very little progress. I'd really appreciate some help with the above error and the problem of getting persistent credentials in general.
This whole structure seems unnecessarily complicated to me. Anybody care to explain why I can't just create a simple Credential object by passing in my Google username and password?
Thanks,
Brian O Carroll, Dublin, Ireland
* Update *
Ok, I've just gotten around the above error and now I have a new one.
The way I got around the first problem was by modifying MyClass.getFlow(). Instead of creating a GoogleClientServices object from a json file, I have used a different version of GoogleAuthorizationCodeFlow.Builder that allows you to enter the client ID and client secret directly as Strings:
flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, "<MY CLIENT ID>", "<MY CLIENT SECRET>", SCOPES).setAccessType("offline").setApprovalPrompt("force").build();
The problem I have now is that I get the following error when I try to use flow (GoogleAuthorizationCodeFlow object) to exchange the authorization code for the Credentials object:
An error occurred: com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_scope"
}
googledrive.MyClass$CodeExchangeException
at googledrive.MyClass.exchangeCode(MyClass.java:185)
at googledrive.MyClass.getCredentials(MyClass.java:262)
at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)
Is there some other scope I should be using for this? I am currently using the array of scopes provided with MyClass:
private static final List<String> SCOPES = Arrays.asList(
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile");
Thanks!
I feel your pain. I'm two months in and still getting surprised.
Some of my learnings...
When you request user permissions, specify "offline=true". This will ("sometimes" sic) return a refreshtoken, which is as good as a password with restricted permissions. You can store this and reuse it at any time (until the user revokes it) to fetch an access token.
My feeling is that the Google SDKs are more of a hinderence than a help. One by one, I've stopped using them and now call the REST API directly.
On your last point, you can (just) use the Google clientlogin protocol to access the previous generation of APIs. However this is totally deprecated and will shortly be turned off. OAuth is designed to give fine grained control of authorisation which is intrinsically complex. So although I agree it's complicated, I don't think it's unnecessarily so. We live in a complicated world :-)
Your and mine experiences show that the development community is still in need of a consolidated document and recipes to get this stuff into our rear-view mirrors so we can focus on the task at hand.
Oath2Scopes is imported as follows:
import com.google.api.services.oauth2.Oauth2Scopes;
You need to have the jar file 'google-api-services-oauth2-v2-rev15-1.8.0-beta.jar' in your class path to access that package. It can be downloaded here.
No, I don't know how to get Credentials without having to visit the authorization URL at least once and copy the code. I've modified MyClass to store and retrieve credentials from a database (in my case, it's a simple table that contains userid, accesstoken and refreshtoken). This way I only have to get the authorization code once and once I get the access/refresh tokens, I can reuse them to make a GoogleCredential object. Here's how Imake the GoogleCredential object:
GoogleCredential credential = new GoogleCredential.Builder().setJsonFactory(jsonFactory)
.setTransport(httpTransport).setClientSecrets(clientid, clientsecret).build();
credential.setAccessToken(accessToken);
credential.setRefreshToken(refreshToken);
Just enter your clientid, clientsecret, accessToken and refreshToken above.
I don't really have a whole lot of time to separate and tidy up my entire code to post it up here but if you're still having problems, let me know and I'll see what I can do. Although, you are effectively asking a blind man for directions. My understanding of this whole system is very sketchy!
Cheers,
Brian
Ok, I've finally solved the second problem above and I'm finally getting a working GoogleCredential object with an access token and a refresh token.
I kept trying to solve the scopes problem by modifying the list of scopes in MyClass (the one that manages credentials). In the end I needed to adjust the scopes in my modified version of DriveCommandLine (the one that's originally used to get an authorization code). I added 2 scopes from Oauth2Scopes:
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET,
Arrays.asList(DriveScopes.DRIVE, Oauth2Scopes.USERINFO_EMAIL, Oauth2Scopes.USERINFO_PROFILE))
.setAccessType("offline").setApprovalPrompt("force").build();
Adding the scopes for user information allowed me to get the userid later in MyClass. I can now use the userid to store the credentials in a database for re-use (without having to get the user to go to a URL each time). I also set the access type to "offline" as suggested by pinoyyid.