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 , as well as registered redirects and the appropriately selected API Permissions.
To run the below demo, grab the 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
.
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 appsettings.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:
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 appsettings.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"
}