# Graph Delegated Authorization + DataVerse

This demo shows how you would authorize a token call to Microsoft Graph for delegated permissions where a token response is required.

This setup involves an app registration in [Azure Portal](https://portal.azure.com/), as well as registered redirects and the appropriately selected API Permissions.

To run the below demo, grab the [Web Host Utilities](https://docs.perigee.software/blueprints/web-host-utilities) and drop it into your project.

Our redirect is `https://localhost:7201/api/token` - which is why our call to map the incoming HTTP request is `/api/token`.

```csharp
PerigeeApplication.ApplicationNoInit("GraphDemo", (c) =>
{
    //Graph and token endpoint
    var dvGraph = new GraphClient(
        c.GetValue<string>("graph:tenant"), 
        c.GetValue<string>("graph:client"), 
        c.GetValue<string>("graph:secret"), 
        c.GetValue<string>("graph:scope"), 
        c.GetValue<string>("graph:redirect"), 
        "", 
        c.GetLogger<Program>());
    
    //Add token receive endpoint
    c.AddMinimalAPI("TokenReceiver", 7201, (w) => { 
            w.MapGet("/api/token", ([FromQuery] string code, GraphClient graph) => { CredentialStore.RefreshAuthorizationCode(graph.credentialName, code); return Results.Ok("Got the new code! Thanks!"); }); }, 
            (b,s) => s.AddSingleton<GraphClient>(dvGraph));

    //Await a valid credential on load
    var cred = CredentialStore.AwaitValidCredential(dvGraph.credentialName, c.GetCancellationToken()).GetAwaiter().GetResult();
    c.GetLogger<_PerigeeStartup>().LogInformation("Authorized Account: {acc}", cred.JWTGetValue(cred.DecodeJWT(cred.Authorization), "unique_name"));

});
```

The <mark style="color:red;">`appsettings.json`</mark>:

```json
"graph": {
  "tenant": "tenantguid",
  "client": "clientguid",
  "secret": "secretkey",
  "scope": "user.read Channel.ReadBasic.All Team.ReadBasic.All offline_access",
  "redirect": "https://localhost:7201/api/token"
}
```

It's very important to include **`offline_access`** if you want to be able to refresh the token automatically.

## For DataVerse

If you're trying to communicate with DataVerse, simply change the domain and scope parameters:

```csharp
PerigeeApplication.ApplicationNoInit("GraphDemo", (c) =>
{
    //Graph and token endpoint
    var dvGraph = new GraphAPI(
        c.GetValue<string>("graph:tenant"), 
        c.GetValue<string>("graph:client"), 
        c.GetValue<string>("graph:secret"), 
        c.GetValue<string>("graph:scope"), 
        c.GetValue<string>("graph:redirect"), 
        c.GetValue<string>("graph:domain"), 
        c.GetLogger<Program>());
    
    //Add token receive endpoint
    c.AddMinimalAPI("TokenReceiver", 7201, (w) => { 
            w.MapGet("/api/token", ([FromQuery] string code, GraphClient graph) => { CredentialStore.RefreshAuthorizationCode(graph.credentialName, code); return Results.Ok("Got the new code! Thanks!"); }); }, 
            (b,s) => s.AddSingleton<GraphClient>(dvGraph));

    //Await a valid credential on load
    var cred = CredentialStore.AwaitValidCredential(dvGraph.credentialName, c.GetCancellationToken()).GetAwaiter().GetResult();
    c.GetLogger<_PerigeeStartup>().LogInformation("Authorized Account: {acc}", cred.JWTGetValue(cred.DecodeJWT(cred.Authorization), "unique_name"));
    
    //Pull DV
    var Employees = dvGraph.GetDataVerseTable<Employees>("cr521_employees");

});
```

The <mark style="color:red;">`appsettings.json`</mark>:

```json
"graph": {
  "tenant": "tenantguid",
  "client": "clientguid",
  "secret": "secretkey",
  "domain": "https://org1234567.api.crm.dynamics.com"
  "scope": "https://org1234567.api.crm.dynamics.com/.default offline_access",
  "redirect": "https://localhost:7201/api/token"
}
```
