Skip to content

Commit

Permalink
feat: BoxCCGAuth add User and Admin clients factory methods without…
Browse files Browse the repository at this point in the history
… initial token (#883)

* feat: `BoxCCGAuth` add User and Admin clients factory methods without initial token

* fix: add configure awaits

* fix: 👌 configure await

* docu(CCG): add new admin/client factory method examples

* docu: fix invalid links

* docu: 👌 typo
  • Loading branch information
JanVargovsky authored Jan 13, 2023
1 parent 84bb80c commit c1337fc
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 13 deletions.
22 changes: 22 additions & 0 deletions Box.V2.Test/BoxCCGAuthTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand All @@ -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));
}
}
}
27 changes: 27 additions & 0 deletions Box.V2/CCGAuth/BoxCCGAuth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ public IBoxClient AdminClient(string adminToken, string asUser = null, bool? sup
return adminClient;
}

/// <summary>
/// Create admin BoxClient
/// </summary>
/// <param name="asUser">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</param>
/// <param name="suppressNotifications">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.</param>
/// <returns>BoxClient that uses CCG authentication</returns>
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;
}

/// <summary>
/// Create user BoxClient using a user access token
/// </summary>
Expand All @@ -64,6 +78,19 @@ public IBoxClient UserClient(string userToken, string userId)
return userClient;
}

/// <summary>
/// Create user BoxClient
/// </summary>
/// <param name="userId">Id of the user</param>
/// <returns>BoxClient that uses CCG authentication</returns>
public IBoxClient UserClient(string userId)
{
var authRepo = new CCGAuthRepository(this, userId);
var userClient = new BoxClient(_boxConfig, authRepo);

return userClient;
}

/// <summary>
/// Get admin token by posting data to auth url
/// </summary>
Expand Down
14 changes: 12 additions & 2 deletions Box.V2/CCGAuth/CCGAuthRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class CCGAuthRepository : IAuthRepository
public string UserId { get; private set; }

/// <summary>
/// Event fired when session is invalidated
/// Event fired when session is invalidated
/// </summary>
public event EventHandler SessionInvalidated;

Expand All @@ -47,6 +47,16 @@ public CCGAuthRepository(OAuthSession session, BoxCCGAuth boxCCGAuth, string use
UserId = userId;
}

/// <summary>
/// Constructor CCG auth repository
/// </summary>
/// <param name="boxCCGAuth">CCG authentication</param>
/// <param name="userId">Id of the user</param>
public CCGAuthRepository(BoxCCGAuth boxCCGAuth, string userId = null)
: this(null, boxCCGAuth, userId)
{
}

/// <summary>
/// Not used for this type of authentication
/// </summary>
Expand All @@ -67,7 +77,7 @@ public Task LogoutAsync()
}

/// <summary>
/// Retrieves a new access token using BoxCCGAuth
/// Retrieves a new access token using BoxCCGAuth
/// </summary>
/// <param name="accessToken">This input is not used. Could be set to null</param>
/// <returns>OAuth session</returns>
Expand Down
10 changes: 5 additions & 5 deletions Box.V2/Managers/BoxResourceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -74,7 +73,7 @@ protected async Task<IBoxResponse<T>> ToResponseAsync<T>(IBoxRequest request, bo
where T : class
{
AddDefaultHeaders(request);
AddAuthorization(request);
await AddAuthorizationAsync(request).ConfigureAwait(false);
var response = await ExecuteRequest<T>(request, queueRequest).ConfigureAwait(false);

return converter != null ? response.ParseResults(converter) : response.ParseResults(_converter);
Expand Down Expand Up @@ -108,13 +107,14 @@ protected async Task<IBoxResponse<T>> RetryExpiredTokenRequest<T>(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<T>(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);

Expand Down
27 changes: 21 additions & 6 deletions docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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

Expand Down

0 comments on commit c1337fc

Please sign in to comment.