diff --git a/Box.V2.Test/BoxCCGAuthTest.cs b/Box.V2.Test/BoxCCGAuthTest.cs
index 3e7b0eb45..1d7508596 100644
--- a/Box.V2.Test/BoxCCGAuthTest.cs
+++ b/Box.V2.Test/BoxCCGAuthTest.cs
@@ -100,6 +100,17 @@ public void UserClient_ShouldReturnUserClientWithSession()
Assert.IsNotNull(userClient.Auth.Session);
}
+ [TestMethod]
+ public void UserClient_WithoutInitialToken_ShouldReturnUserClient()
+ {
+ // Act
+ var userClient = _ccgAuth.UserClient("22222");
+
+ // Assert
+ Assert.IsInstanceOfType(userClient, typeof(BoxClient));
+ Assert.IsInstanceOfType(userClient.Auth, typeof(CCGAuthRepository));
+ }
+
[TestMethod]
public void AdminClient_ShouldReturnAdminClientWithSession()
{
@@ -111,5 +122,16 @@ public void AdminClient_ShouldReturnAdminClientWithSession()
Assert.IsInstanceOfType(adminClient.Auth, typeof(CCGAuthRepository));
Assert.IsNotNull(adminClient.Auth.Session);
}
+
+ [TestMethod]
+ public void AdminClient_WithoutInitialToken_ShouldReturnAdminClient()
+ {
+ // Act
+ var adminClient = _ccgAuth.AdminClient("22222", true);
+
+ // Assert
+ Assert.IsInstanceOfType(adminClient, typeof(BoxClient));
+ Assert.IsInstanceOfType(adminClient.Auth, typeof(CCGAuthRepository));
+ }
}
}
diff --git a/Box.V2/CCGAuth/BoxCCGAuth.cs b/Box.V2/CCGAuth/BoxCCGAuth.cs
index fdb2ace86..0eca4a05f 100644
--- a/Box.V2/CCGAuth/BoxCCGAuth.cs
+++ b/Box.V2/CCGAuth/BoxCCGAuth.cs
@@ -49,6 +49,20 @@ public IBoxClient AdminClient(string adminToken, string asUser = null, bool? sup
return adminClient;
}
+ ///
+ /// Create admin BoxClient
+ ///
+ /// The user ID to set as the 'As-User' header parameter; used to make calls in the context of a user using an admin token
+ /// Whether or not to suppress both email and webhook notifications. Typically used for administrative API calls. Your application must have “Manage an Enterprise” scope, and the user making the API calls is a co-admin with the correct "Edit settings for your company" permission.
+ /// BoxClient that uses CCG authentication
+ public IBoxClient AdminClient(string asUser = null, bool? suppressNotifications = null)
+ {
+ var authRepo = new CCGAuthRepository(this);
+ var adminClient = new BoxClient(_boxConfig, authRepo, asUser: asUser, suppressNotifications: suppressNotifications);
+
+ return adminClient;
+ }
+
///
/// Create user BoxClient using a user access token
///
@@ -64,6 +78,19 @@ public IBoxClient UserClient(string userToken, string userId)
return userClient;
}
+ ///
+ /// Create user BoxClient
+ ///
+ /// Id of the user
+ /// BoxClient that uses CCG authentication
+ public IBoxClient UserClient(string userId)
+ {
+ var authRepo = new CCGAuthRepository(this, userId);
+ var userClient = new BoxClient(_boxConfig, authRepo);
+
+ return userClient;
+ }
+
///
/// Get admin token by posting data to auth url
///
diff --git a/Box.V2/CCGAuth/CCGAuthRepository.cs b/Box.V2/CCGAuth/CCGAuthRepository.cs
index 5a28f07d8..b07dbe175 100644
--- a/Box.V2/CCGAuth/CCGAuthRepository.cs
+++ b/Box.V2/CCGAuth/CCGAuthRepository.cs
@@ -25,7 +25,7 @@ public class CCGAuthRepository : IAuthRepository
public string UserId { get; private set; }
///
- /// Event fired when session is invalidated
+ /// Event fired when session is invalidated
///
public event EventHandler SessionInvalidated;
@@ -47,6 +47,16 @@ public CCGAuthRepository(OAuthSession session, BoxCCGAuth boxCCGAuth, string use
UserId = userId;
}
+ ///
+ /// Constructor CCG auth repository
+ ///
+ /// CCG authentication
+ /// Id of the user
+ public CCGAuthRepository(BoxCCGAuth boxCCGAuth, string userId = null)
+ : this(null, boxCCGAuth, userId)
+ {
+ }
+
///
/// Not used for this type of authentication
///
@@ -67,7 +77,7 @@ public Task LogoutAsync()
}
///
- /// Retrieves a new access token using BoxCCGAuth
+ /// Retrieves a new access token using BoxCCGAuth
///
/// This input is not used. Could be set to null
/// OAuth session
diff --git a/Box.V2/Managers/BoxResourceManager.cs b/Box.V2/Managers/BoxResourceManager.cs
index 569853aff..c434ecfbd 100644
--- a/Box.V2/Managers/BoxResourceManager.cs
+++ b/Box.V2/Managers/BoxResourceManager.cs
@@ -14,7 +14,6 @@
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
-using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -74,7 +73,7 @@ protected async Task> ToResponseAsync(IBoxRequest request, bo
where T : class
{
AddDefaultHeaders(request);
- AddAuthorization(request);
+ await AddAuthorizationAsync(request).ConfigureAwait(false);
var response = await ExecuteRequest(request, queueRequest).ConfigureAwait(false);
return converter != null ? response.ParseResults(converter) : response.ParseResults(_converter);
@@ -108,13 +107,14 @@ protected async Task> RetryExpiredTokenRequest(IBoxRequest re
{
OAuthSession newSession = await _auth.RefreshAccessTokenAsync(request.Authorization).ConfigureAwait(false);
AddDefaultHeaders(request);
- AddAuthorization(request, newSession.AccessToken);
+ await AddAuthorizationAsync(request, newSession.AccessToken).ConfigureAwait(false);
return await _service.ToResponseAsync(request).ConfigureAwait(false);
}
- protected void AddAuthorization(IBoxRequest request, string accessToken = null)
+ protected async Task AddAuthorizationAsync(IBoxRequest request, string accessToken = null)
{
- var auth = accessToken ?? _auth.Session.AccessToken;
+ var auth = accessToken ??
+ (_auth.Session ?? await _auth.RefreshAccessTokenAsync(null).ConfigureAwait(false)).AccessToken;
var authString = string.Format(CultureInfo.InvariantCulture, Constants.V2AuthString, auth);
diff --git a/docs/authentication.md b/docs/authentication.md
index 95e4d078c..db1d1b78c 100644
--- a/docs/authentication.md
+++ b/docs/authentication.md
@@ -50,7 +50,7 @@ var client = new BoxClient(config, session);
Server auth allows your application to authenticate itself with the Box API
for a given enterprise. By default, your application has a
-[Service Account](https://developer.box.com/en/guides/authentication/user-types/)
+[Service Account](https://developer.box.com/guides/getting-started/user-types/service-account/)
that represents it and can perform API calls. The Service Account is separate
from the Box accounts of the application developer and the enterprise admin of
any enterprise that has authorized the app — files stored in that account are
@@ -85,8 +85,7 @@ adminClient.Auth.SessionAuthenticated += delegate(object o, SessionAuthenticated
};
```
-App auth applications also often have associated App Users, which are
-[created and managed directly by the application](https://developer.box.com/en/guides/authentication/user-types/)
+App auth applications also often have associated [App Users](https://developer.box.com/guides/getting-started/user-types/app-users/), which are created and managed directly by the application
— they do not have normal login credentials, and can only be accessed through
the Box API by the application that created them. You may authenticate as the
Service Account to provision and manage users, or as an individual app user to
@@ -115,7 +114,7 @@ Server auth allows your application to authenticate itself with the Box API
for a given enterprise.
Client Credentials Grant (CCG) allows you to authenticate by providing `clientId` and `clientSecret` and `enterpriseId` of your app.
By default, your application has a
-[Service Account](https://developer.box.com/en/guides/authentication/user-types/)
+[Service Account](https://developer.box.com/guides/getting-started/user-types/service-account/)
that represents it and can perform API calls. The Service Account is separate
from the Box accounts of the application developer and the enterprise admin of
any enterprise that has authorized the app — files stored in that account are
@@ -130,6 +129,10 @@ var boxConfig = new BoxConfigBuilder("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")
.SetEnterpriseId("YOUR_ENTERPRISE_ID")
.Build();
var boxCCG = new BoxCCGAuth(boxConfig);
+```
+
+There are two ways to create an admin client, the first one uses explicit admin token:
+```c#
var adminToken = await boxCCG.AdminTokenAsync(); //valid for 60 minutes so should be cached and re-used
IBoxClient adminClient = boxCCG.AdminClient(adminToken);
adminClient.Auth.SessionAuthenticated += delegate(object o, SessionAuthenticatedEventArgs e)
@@ -139,8 +142,12 @@ adminClient.Auth.SessionAuthenticated += delegate(object o, SessionAuthenticated
};
```
-App auth applications also often have associated App Users, which are
-[created and managed directly by the application](https://developer.box.com/en/guides/authentication/user-types/)
+Second way leaves token management (caching) to the `Auth`, a new token is retrieved before the first call. Keep in mind that if you create multiple `adminClient` instances, the token won't be shared, it is expected that the `adminClient` instance is reused.
+```c#
+IBoxClient adminClient = boxCCG.AdminClient();
+```
+
+App auth applications also often have associated [App Users](https://developer.box.com/guides/getting-started/user-types/app-users/), which are created and managed directly by the application
— they do not have normal login credentials, and can only be accessed through
the Box API by the application that created them. You may authenticate as the
Service Account to provision and manage users, or as an individual app user to
@@ -155,6 +162,10 @@ instance as in the above examples, similarly to creating a Service Account clien
var boxConfig = new BoxConfigBuilder("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")
.Build();
var boxCCG = new BoxCCGAuth(boxConfig);
+```
+
+Variant with explicit initial token:
+```c#
var userToken = await boxCCG.UserTokenAsync("USER_ID"); //valid for 60 minutes so should be cached and re-used
IBoxClient userClient = boxCCG.UserClient(userToken, "USER_ID");
userClient.Auth.SessionAuthenticated += delegate(object o, SessionAuthenticatedEventArgs e)
@@ -163,6 +174,10 @@ userClient.Auth.SessionAuthenticated += delegate(object o, SessionAuthenticatedE
// cache the new access token
};
```
+Variant without initial token:
+```c#
+IBoxClient userClient = boxCCG.UserClient("USER_ID");
+```
### Traditional 3-Legged OAuth2