Skip to content

Commit

Permalink
v0.6 Alpha (#4)
Browse files Browse the repository at this point in the history
* WIP OpenFGA

* Update README.md

* Update README.md

* Add additional samples

* Update Package.Build.props

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Improve minimal API example
  • Loading branch information
Hawxy authored Sep 1, 2022
1 parent 5086dab commit 4880b62
Show file tree
Hide file tree
Showing 23 changed files with 177 additions and 109 deletions.
4 changes: 2 additions & 2 deletions Package.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>0.5.0-alpha</Version>
<Version>0.6.0-alpha</Version>
<Authors>Hawxy</Authors>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
Expand All @@ -20,4 +20,4 @@
<_Parameter1>Fga.Net.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
</Project>
</Project>
85 changes: 58 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,65 @@
# Auth0 FGA for Worker Services & ASP.NET Core
## OpenFGA & Auth0 FGA for ASP.NET Core + Worker Services

[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Fga.Net.DependencyInjection?label=Fga.Net.DependencyInjection&style=flat-square)](https://www.nuget.org/packages/Fga.Net.DependencyInjection)
[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Fga.Net.AspNetCore?label=Fga.Net.AspNetCore&style=flat-square)](https://www.nuget.org/packages/Fga.Net.AspNetCore)

#### Note: This project is in its early stages and will have breaking changes as FGA matures.

### Packages
- **Fga.Net.DependencyInjection**: Provides dependency injection extensions for Auth0.Fga
**`Fga.Net.DependencyInjection`**: Provides dependency injection/configuration extensions for [OpenFga.Sdk](https://github.com/openfga/dotnet-sdk)

- **Fga.Net.AspNetCore**: Additionally includes Authorization middleware to support FGA checks as part of a request's lifecycle.
**`Fga.Net.AspNetCore`**: Additionally includes Authorization middleware to support FGA checks as part of a request's lifecycle.

## Getting Started

#### Note: This project is in its early stages and will have breaking changes as FGA matures.
This package is compatible with the OSS OpenFGA as well as the managed Auth0 FGA service.

Please ensure you have a basic understanding of how FGA works before continuing: https://docs.fga.dev/
Please ensure you have a basic understanding of how FGA works before continuing: [OpenFGA Docs](https://openfga.dev/) or [Auth0 FGA Docs](https://docs.fga.dev/)

## ASP.NET Core Setup

Before getting started, ensure you have a Store ID, Client ID, and Client Secret ready from [How to get your API keys](https://docs.fga.dev/integration/getting-your-api-keys).
This tutorial assumes you have authentication setup within your project, such as [JWT bearer authentication via Auth0](https://auth0.com/docs/quickstart/backend/aspnet-core-webapi/01-authorization).

Install `Fga.Net.AspNetCore` from Nuget before continuing.

### Auth0 FGA

I'm also assuming you have authentication setup within your project, such as [JWT bearer authentication via Auth0](https://auth0.com/docs/quickstart/backend/aspnet-core-webapi/01-authorization).
Ensure you have a Store ID, Client ID, and Client Secret ready from [How to get your API keys](https://docs.fga.dev/integration/getting-your-api-keys).


1. Install `Fga.Net.AspNetCore` from Nuget.
2. Add your `StoreId`, `ClientId` and `ClientSecret` to your application configuration, ideally via the [dotnet secrets manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows#enable-secret-storage).
3. Add the following code to your ASP.NET Core configuration:
1. Add your `StoreId`, `ClientId` and `ClientSecret` to your application configuration, ideally via the [dotnet secrets manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows#enable-secret-storage).
2. Add the following code to your ASP.NET Core services configuration:
```cs
// Registers the Auth0FgaApi client
builder.Services.AddAuth0Fga(x =>
builder.Services.AddOpenFga(x =>
{
x.ClientId = builder.Configuration["Auth0Fga:ClientId"];
x.ClientSecret = builder.Configuration["Auth0Fga:ClientSecret"];
x.WithAuth0FgaDefaults(builder.Configuration["Auth0Fga:ClientId"], builder.Configuration["Auth0Fga:ClientSecret"]);

x.StoreId = builder.Configuration["Auth0Fga:StoreId"];
});
```

The `WithAuth0FgaDefaults` extension will configure the relevant OpenFGA client settings to work with Auth0 FGA's US environment.

### OpenFGA

OpenFGA configuration is very similar to the [SDK Setup Guide](https://openfga.dev/docs/getting-started/setup-sdk-client)

1. Add the FGA `ApiScheme`, `ApiHost` & `StoreId` to your application configuration.
2. Add the following code to your ASP.NET Core configuration:
```cs
builder.Services.AddOpenFga(x =>
{
x.ApiScheme = builder.Configuration["Fga:ApiScheme"];
x.ApiHost = builder.Configuration["Fga:ApiHost"];
x.StoreId = builder.Configuration["Fga:StoreId"];
});
```

### Authorization Policy Setup

Now we'll need to setup our authorization middleware like so:

```cs
// Register the authorization policy
builder.Services.AddAuthorization(options =>
{
Expand All @@ -43,7 +70,7 @@ builder.Services.AddAuthorization(options =>
});
```

4. Create an attribute that inherits from `TupleCheckAttribute`. From here, you can pull the metadata you require to perform your tuple checks out of the HTTP request.
Next, create an attribute that inherits from `TupleCheckAttribute`. From here, you can pull the metadata you require to perform your tuple checks out of the HTTP request.
For example, an equivalent to the [How To Integrate Within A Framework](https://docs.fga.dev/integration/framework) example would be:
```cs
public class EntityAuthorizationAttribute : TupleCheckAttribute
Expand Down Expand Up @@ -72,7 +99,7 @@ public class EntityAuthorizationAttribute : TupleCheckAttribute
}
```

5. Apply the `Authorize` and `EntityAuthorization` attributes to your controller(s):
Now apply the `Authorize` and `EntityAuthorization` attributes to your controller(s):
```cs
// Traditional Controllers
[ApiController]
Expand All @@ -89,10 +116,9 @@ public class EntityAuthorizationAttribute : TupleCheckAttribute
}

// Minimal APIs
app.MapGet("/viewminimal/{documentId}",
[Authorize(FgaAuthorizationDefaults.PolicyKey)]
[EntityAuthorization("doc", "documentId")]
(documentId) => Task.FromResult(documentId));
app.MapGet("/viewminimal/{documentId}", (string documentId) => Task.FromResult(documentId))
.RequireAuthorization(FgaAuthorizationDefaults.PolicyKey)
.WithMetadata(new EntityAuthorizationAttribute("doc", "documentId"));
```

If you need to manually perform checks, inject the `Auth0FgaApi` as required.
Expand All @@ -101,23 +127,28 @@ An additional pre-made attribute that allows all tuple values to be hardcoded st

## Worker Service / Generic Host Setup

`Fga.Net.DependencyInjection` ships with the `AddAuth0FgaClient` service collection extension that handles all required wire-up.
`Fga.Net.DependencyInjection` ships with the `AddOpenFgaClient` service collection extension that handles all required wire-up.

To get started:

1. Install `Fga.Net.DependencyInjection`
2. Add your `StoreId`, `ClientId` and `ClientSecret` to your application configuration, ideally via the [dotnet secrets manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows#enable-secret-storage).
2. Add your `StoreId`, `ClientId` and `ClientSecret` Auth0 FGA configuration **OR** `ApiScheme`, `ApiHost` & `StoreId` OpenFGA configuration to your application configuration, ideally via the [dotnet secrets manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows#enable-secret-storage).
3. Register the authorization client:

```cs
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddAuth0FgaClient(config =>
services.AddOpenFgaClient(config =>
{
config.ClientId = context.Configuration["Auth0Fga:ClientId"];
config.ClientSecret = context.Configuration["Auth0Fga:ClientSecret"];
// Auth0 FGA
config.WithAuth0FgaDefaults(context.Configuration["Auth0Fga:ClientId"], context.Configuration["Auth0Fga:ClientSecret"]);
config.StoreId = context.Configuration["Auth0Fga:StoreId"];

// OpenFGA
config.ApiScheme = context.Configuration["Fga:ApiScheme"];
config.ApiHost = context.Configuration["Fga:ApiHost"];
config.StoreId = context.Configuration["Fga:StoreId"];
});

services.AddHostedService<MyBackgroundWorker>();
Expand Down Expand Up @@ -148,8 +179,8 @@ public class MyBackgroundWorker : BackgroundService

## Standalone client setup

See the [Auth0.Fga docs](https://github.com/auth0-lab/fga-dotnet-sdk)
See the [OpenFGA.Sdk docs](https://openfga.dev/docs/getting-started/setup-sdk-client)

## Disclaimer

I am not affiliated with nor represent Auth0. All support queries regarding the underlying service should go to the [Auth0 Labs Discord](https://discord.gg/8naAwJfWN6).
I am not affiliated with nor represent Auth0 or OpenFGA. All support queries regarding the underlying service should go to the [Auth0 Labs Discord](https://discord.gg/8naAwJfWN6).
8 changes: 0 additions & 8 deletions build/Build.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
using System;
using System.Linq;
using Nuke.Common;
using Nuke.Common.CI;
using Nuke.Common.Execution;
using Nuke.Common.Git;
using Nuke.Common.IO;
using Nuke.Common.ProjectModel;
using Nuke.Common.Tooling;
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Utilities.Collections;
using static Nuke.Common.EnvironmentInfo;
using static Nuke.Common.IO.FileSystemTasks;
using static Nuke.Common.IO.PathConstruction;
using static Nuke.Common.Tools.DotNet.DotNetTasks;

[ShutdownDotNetAfterServerBuild]
Expand Down
2 changes: 1 addition & 1 deletion build/_build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Nuke.Common" Version="6.1.0" />
<PackageReference Include="Nuke.Common" Version="6.2.1" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.8" />
</ItemGroup>

<ItemGroup>
Expand Down
26 changes: 18 additions & 8 deletions samples/Fga.Example.AspNetCore/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
using Fga.Example.AspNetCore;
using Fga.Net.AspNetCore;
using Fga.Net.AspNetCore.Authorization;
using Fga.Net.DependencyInjection;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;

var builder = WebApplication.CreateBuilder(args);
Expand All @@ -27,13 +27,24 @@
};
});

builder.Services.AddAuth0Fga(x =>

// Auth0 FGA
builder.Services.AddOpenFga(x =>
{
x.ClientId = builder.Configuration["Auth0Fga:ClientId"];
x.ClientSecret = builder.Configuration["Auth0Fga:ClientSecret"];
x.WithAuth0FgaDefaults(builder.Configuration["Auth0Fga:ClientId"], builder.Configuration["Auth0Fga:ClientSecret"]);
x.StoreId = builder.Configuration["Auth0Fga:StoreId"];
});


// OpenFGA
/*builder.Services.AddOpenFga(x =>
{
x.ApiScheme = builder.Configuration["Fga:ApiScheme"];
x.ApiHost = builder.Configuration["Fga:ApiHost"];
x.StoreId = builder.Configuration["Fga:StoreId"];
});*/

builder.Services.AddAuthorization(options =>
{
options.AddPolicy(FgaAuthorizationDefaults.PolicyKey,
Expand All @@ -56,9 +67,8 @@

app.MapControllers();

app.MapGet("/viewminimal/{documentId}",
[Authorize(FgaAuthorizationDefaults.PolicyKey)]
[EntityAuthorization("doc", "documentId")]
(documentId) => Task.FromResult(documentId));
app.MapGet("/viewminimal/{documentId}", (string documentId) => Task.FromResult(documentId))
.RequireAuthorization(FgaAuthorizationDefaults.PolicyKey)
.WithMetadata(new EntityAuthorizationAttribute("doc", "documentId"));

app.Run();
6 changes: 3 additions & 3 deletions samples/Fga.Example.GenericHost/MyService.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using Auth0.Fga.Api;
using OpenFga.Sdk.Api;

namespace Fga.Example.GenericHost
{
public class MyBackgroundWorker : BackgroundService
{
private readonly Auth0FgaApi _authorizationClient;
private readonly OpenFgaApi _authorizationClient;

public MyBackgroundWorker(Auth0FgaApi authorizationClient)
public MyBackgroundWorker(OpenFgaApi authorizationClient)
{
_authorizationClient = authorizationClient;
}
Expand Down
12 changes: 8 additions & 4 deletions samples/Fga.Example.GenericHost/Program.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
using Fga.Example.GenericHost;
using Fga.Net;
using Fga.Net.DependencyInjection;

var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddAuth0FgaClient(config =>
services.AddOpenFgaClient(config =>
{
config.ClientId = context.Configuration["Auth0Fga:ClientId"];
config.ClientSecret = context.Configuration["Auth0Fga:ClientSecret"];
// Auth0 FGA
config.WithAuth0FgaDefaults(context.Configuration["Auth0Fga:ClientId"], context.Configuration["Auth0Fga:ClientSecret"]);
config.StoreId = context.Configuration["Auth0Fga:StoreId"];
// OpenFGA
config.ApiScheme = context.Configuration["Fga:ApiScheme"];
config.ApiHost = context.Configuration["Fga:ApiHost"];
config.StoreId = context.Configuration["Fga:StoreId"];
});
services.AddHostedService<MyBackgroundWorker>();
Expand Down
8 changes: 4 additions & 4 deletions src/Fga.Net.AspNetCore/Authorization/FgaCheckDecorator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Auth0.Fga.Api;
using Auth0.Fga.Model;
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Model;

namespace Fga.Net.AspNetCore.Authorization;

Expand All @@ -8,13 +8,13 @@ namespace Fga.Net.AspNetCore.Authorization;
/// </summary>
public class FgaCheckDecorator : IFgaCheckDecorator
{
private readonly Auth0FgaApi _auth0FgaApi;
private readonly OpenFgaApi _auth0FgaApi;

/// <summary>
///
/// </summary>
/// <param name="auth0FgaApi"></param>
public FgaCheckDecorator(Auth0FgaApi auth0FgaApi)
public FgaCheckDecorator(OpenFgaApi auth0FgaApi)
{
_auth0FgaApi = auth0FgaApi;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ limitations under the License.
*/
#endregion

using Auth0.Fga.Model;
using Fga.Net.AspNetCore.Authorization.Attributes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using OpenFga.Sdk.Model;

namespace Fga.Net.AspNetCore.Authorization;

Expand Down
8 changes: 4 additions & 4 deletions src/Fga.Net.AspNetCore/Controllers/FgaControllerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ limitations under the License.
*/
#endregion

using Auth0.Fga.Api;
using Auth0.Fga.Model;
using Microsoft.AspNetCore.Mvc;
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Model;

namespace Fga.Net.AspNetCore.Controllers;

Expand All @@ -27,12 +27,12 @@ namespace Fga.Net.AspNetCore.Controllers;
/// </summary>
public class FgaControllerBase : ControllerBase
{
private readonly Auth0FgaApi _client;
private readonly OpenFgaApi _client;
/// <summary>
///
/// </summary>
/// <param name="client"></param>
public FgaControllerBase(Auth0FgaApi client)
public FgaControllerBase(OpenFgaApi client)
{
_client = client;
}
Expand Down
10 changes: 5 additions & 5 deletions src/Fga.Net.AspNetCore/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ limitations under the License.
*/
#endregion

using Auth0.Fga.Api;
using Fga.Net.AspNetCore.Authorization;
using Fga.Net.DependencyInjection;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using OpenFga.Sdk.Api;

namespace Fga.Net.AspNetCore;

Expand All @@ -30,16 +30,16 @@ namespace Fga.Net.AspNetCore;
public static class ServiceCollectionExtensions
{
/// <summary>
/// Adds and configures an <see cref="FineGrainedAuthorizationHandler"/> along with a <see cref="Auth0FgaApi"/>.
/// Adds and configures an <see cref="FineGrainedAuthorizationHandler"/> along with a <see cref="OpenFgaApi"/>.
/// </summary>
/// <param name="collection">The service collection</param>
/// <param name="config">The delegate for the <see cref="FgaClientConfiguration"/> that will be used to configure the <see cref="Auth0FgaApi"/></param>
/// <param name="config">The delegate for the <see cref="FgaClientConfiguration"/> that will be used to configure the <see cref="OpenFgaApi"/></param>
/// <returns>The service collection</returns>
public static IServiceCollection AddAuth0Fga(this IServiceCollection collection, Action<FgaClientConfiguration> config)
public static IServiceCollection AddOpenFga(this IServiceCollection collection, Action<FgaClientConfiguration> config)
{
ArgumentNullException.ThrowIfNull(config);

collection.AddAuth0FgaClient(config);
collection.AddOpenFgaClient(config);
collection.AddScoped<IFgaCheckDecorator, FgaCheckDecorator>();
collection.AddScoped<IAuthorizationHandler, FineGrainedAuthorizationHandler>();
return collection;
Expand Down
Loading

0 comments on commit 4880b62

Please sign in to comment.