Microsoft Graph C# Schedule Meeting - c#

I'm trying to schedule events in my O365 user calendars.
I'm using an administrator account, creating a GraphServiceClient on authentication.
There are no errors (apparently) but the event is not created. Neither on the account used nor on the Attendees.
It seems to me that the problem is in the authorization of the GraphServiceClient. I already checked in the Azure portal and the user has "Calendars.ReadWrite" permission.
Any help, please?
try
{
var scopes = new[] { "Calendars.ReadWrite.All" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";
Configuracoes Dados = new Configuracoes();
// Values from app registration
string clientId = Dados.EMailCV.ToString();
string clientSecret = Dados.PasswordCV.ToString();
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// This is the incoming token to exchange using on-behalf-of flow
var oboToken = "JWT_TOKEN_TO_EXCHANGE";
var cca = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.WithClientSecret(clientSecret)
.Build();
// DelegateAuthenticationProvider is a simple auth provider implementation
// that allows you to define an async function to retrieve a token
// Alternatively, you can create a class that implements IAuthenticationProvider
// for more complex scenarios
var authProvider = new DelegateAuthenticationProvider(async (request) =>
{
// Use Microsoft.Identity.Client to retrieve token
var assertion = new UserAssertion(oboToken);
var result = await cca.AcquireTokenOnBehalfOf(scopes, assertion).ExecuteAsync();
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
});
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var #event = new Event
{
Subject = "Let's go for lunch",
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "Does noon work for you?"
},
Start = new DateTimeTimeZone
{
DateTime = "2022-11-04T12:00:00",
TimeZone = "GMT Standard Time"
},
End = new DateTimeTimeZone
{
DateTime = "2017-04-15T14:00:00",
TimeZone = "GMT Standard Time"
},
// Location = new Location
// {
// displayName = "Harry's Bar"
// },
Attendees = new List<Attendee>()
{
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "p560#esenviseu.net",
Name = "Nuno Barros"
},
Type = AttendeeType.Required
}
},
AllowNewTimeProposals = true,
IsOnlineMeeting = true,
OnlineMeetingProvider = OnlineMeetingProviderType.TeamsForBusiness
};
graphClient.Me.Events
.Request()
.Header("Prefer", "outlook.timezone=\"GMT Standard Time\"")
.AddAsync(#event);
}
catch (Exception ex)
{
lblTexto.Text = "Erros!<br>" + ex.Message;
}
finally
{
lblTexto.Text = "Sem erros!";
}

Related

Events not creating for multiple users at same call for the application permission

I have registered the App with application permission in Azure Directory and I am able to get Token and schedule a event by using the Same token for the single User at a time, but when I add the multiple Attendees (vinay#yfdln.onmicrosoft.com,AdeleV#yfdln.onmicrosoft.com) in the list then it's not creating the meeting for another user which I have not mentioned in the
GraphServiceClient(accessToken).Users["AdeleV#yfdln.onmicrosoft.com"].Events.Request().AddAsync(#event);
and am receiving the email saying
Delivery has failed to these recipients or groups:
Vinay#yfdln.onmicrosoft.com
Your message wasn't delivered because the recipient's email provider rejected it.
and I also got Some Error in the mail for
Diagnostic information for administrators:
Generating server: SA0PR19MB4602.namprd19.prod.outlook.com
Vinay#yfdln.onmicrosoft.com
Remote Server returned '550 5.7.501 Service unavailable. Spam abuse detected from IP range. For more information please go to http://go.microsoft.com/fwlink/?LinkId=526653. S(2017052602) [BYAPR19MB3063.namprd19.prod.outlook.com]'
Original message headers:
Received: from SA0PR19MB4602.namprd19.prod.outlook.com
([fe80::d4d8:a608:e081:3249]) by SA0PR19MB4602.namprd19.prod.outlook.com
([fe80::d4d8:a608:e081:3249%7]) with mapi id 15.20.5373.018; Tue, 28 Jun 2022
13:43:23 +0000
MIME-Version: 1.0
Content-Type: text/plain
Date: Tue, 28 Jun 2022 13:43:23 +0000
Message-ID:
<SA0PR19MB4602896A05ED8C22B925567688B89#SA0PR19MB4602.namprd19.prod.outlook.com>
Subject: Schedule From .Net
Code
public static async Task<Event> CreateEvent(string accessToken)
{
Event event1 = new Event();
var #event = new Event
{
Subject = "Schedule From .Net",
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "Test Schedule"
},
Start = new DateTimeTimeZone
{
DateTime = "2022-07-10T12:00:00",
TimeZone = "Pacific Standard Time"
},
End = new DateTimeTimeZone
{
DateTime = "2022-07-10T14:00:00",
TimeZone = "Pacific Standard Time"
},
Location = new Location
{
DisplayName = "OR1"
},
Attendees = new List<Attendee>()
{
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "vinay#yfdln.onmicrosoft.com",
Name = "Vinay"
},
Type = AttendeeType.Required
},
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "AdeleV#yfdln.onmicrosoft.com",
Name = "Adelev"
},
Type = AttendeeType.Required
}
},
TransactionId = Guid.NewGuid().ToString()
};
try
{
event1 = await GraphServiceClient(accessToken).Users["AdeleV#yfdln.onmicrosoft.com"].Events.Request().AddAsync(#event);
}
catch (Exception ex)
{
}
return event1;
}
Can anybody can you please check and suggest how we can schedule for multiple users at thee same time by using the same.
is there any option to change below code to add multiple emails in Users[] array
GraphServiceClient(accessToken).Users["AdeleV#yfdln.onmicrosoft.com"].Events.Request().AddAsync(#event);
to
GraphServiceClient(accessToken).Users["AdeleV#yfdln.onmicrosoft.com,AdeleV#yfdln.onmicrosoft.com"].Events.Request().AddAsync(#event);
but this gives error as below
Code: ResourceNotFound
Message: Resource could not be discovered.
Inner error:
AdditionalData:
date: 2022-06-28T14:41:33
request-id: 41cf2d89-de6d-44df-b42f-1e11d2fe430e
client-request-id: 41cf2d89-de6d-44df-b42f-1e11d2fe430e
ClientRequestId: 41cf2d89-de6d-44df-b42f-1e11d2fe430e
can please suggest which way we have to call
Regards
Srikanth
Sorry pls follow the code below and have a test.
I double confirmed your code and checked the official api document, I noticed that what you wrote is await GraphServiceClient(accessToken).Users["AdeleV#yfdln.onmicrosoft.com"].Events.Request().AddAsync(#event) while the sample code is await graphClient.Me.Calendars["{calendar-id}"].Events.Request().AddAsync(#event);, so you may need to use code GraphServiceClient(accessToken).Users["AdeleV#yfdln.onmicrosoft.com"].Calendars["{calendar-id}"].Events.Request().AddAsync(#event); instead.
public void CreateEvent()
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "your_tenant_name.onmicrosoft.com";
var clientId = "azure_ad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var #event = new Event
{
Subject = "Schedule From .Net",
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "Test Schedule"
},
Start = new DateTimeTimeZone
{
DateTime = "2022-07-10T12:00:00",
TimeZone = "Pacific Standard Time"
},
End = new DateTimeTimeZone
{
DateTime = "2022-07-10T14:00:00",
TimeZone = "Pacific Standard Time"
},
Location = new Location
{
DisplayName = "OR1"
},
Attendees = new List<Attendee>()
{
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "vinay#yfdln.onmicrosoft.com",
Name = "Vinay"
},
Type = AttendeeType.Required
},
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "AdeleV#yfdln.onmicrosoft.com",
Name = "Adelev"
},
Type = AttendeeType.Required
}
},
TransactionId = Guid.NewGuid().ToString()
};
var res = await graphClient.Users["userId"].Calendars["{calendar-id}"].Events.Request().AddAsync(#event);
}

AcquireTokenByAuthorizationCode throw new exception in single tenant application using ASP.NET MVC using Azure Active Directory

I tried this tutorial because I want to use the Microsoft Graph API to create massive teams in Microsoft Teams.
The only difference with the tutorial is that I used the next choice in Authentication section of Azure AD admin center:
"Accounts in this organizational directory only (myuniversity only - Single tenant)"
Because of this I changed my code to use endpoint for single tenant
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = appId,
//Authority = "https://login.microsoftonline.com/common/v2.0",//
Authority = "https://login.microsoftonline.com/{tenantid}/v2.0",
Scope = $"openid email profile offline_access {graphScopes}",
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
// For demo purposes only, see below
ValidateIssuer = false
// In a real multi-tenant app, you would add logic to determine whether the
// issuer was from an authorized tenant
//ValidateIssuer = true,
//IssuerValidator = (issuer, token, tvp) =>
//{
// if (MyCustomTenantValidation(issuer))
// {
// return issuer;
// }
// else
// {
// throw new SecurityTokenInvalidIssuerException("Invalid issuer");
// }
//}
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
}
}
);
}
After authentication of the user the code I run to OnAuthorizationCodeReceivedAsync method but got an exception in AcquireTokenByAuthorizationCode method
Here is the method
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
var idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithClientSecret(appSecret)
.Build();
var accounts = await idClient.GetAccountsAsync();
string message;
string debug;
try
{
string[] scopes = graphScopes.Split(' ');
var result = await idClient.AcquireTokenByAuthorizationCode(scopes, notification.Code).ExecuteAsync();
message = "Access token retrieved.";
debug = result.AccessToken;
}
catch (MsalException ex)
{
message = "AcquireTokenByAuthorizationCodeAsync threw an exception";
debug = ex.Message;
}
var queryString = $"message={message}&debug={debug}";
if (queryString.Length > 2048)
{
queryString = queryString.Substring(0, 2040) + "...";
}
notification.HandleResponse();
notification.Response.Redirect($"/Home/Error?{queryString}");
}
The exception is:
AcquireTokenByAuthorizationCodeAsync threw an exception
AADSTS50194: Application 'application id'(ASP.NET Graph Tutorial) is
not configured as a multi-tenant application. Usage of the /common
endpoint is not supported for such applications created after
'10/15/2018'. Use a tenant-specific endpoint or configure the
application to be multi-tenant. Trace ID:
5f0fbf2e-5d63-40d4-a833-ca8627a02d00
Correlation ID: 3ec4ec7b-0c86-4e2b-a053-9823f977499d Timestamp:
2021-02-16 20:21:03Z
I want to use single-tenant authentication for my organization only
If you want to require AD token from one specific tenant with MSAL.NET, you can tell the SDK from which tenant to obtain the token by mentioning the specific Authority. For more details, please refer to here.
For example
private static string appId = ConfigurationManager.AppSettings["ida:AppId"];
private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
private static string graphScopes = ConfigurationManager.AppSettings["ida:AppScopes"];
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = appId,
Authority = "https://login.microsoftonline.com/<your tenant id>/v2.0",
Scope = $"openid email profile offline_access {graphScopes}",
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
// For demo purposes only, see below
ValidateIssuer = false
// In a real multi-tenant app, you would add logic to determine whether the
// issuer was from an authorized tenant
//ValidateIssuer = true,
//IssuerValidator = (issuer, token, tvp) =>
//{
// if (MyCustomTenantValidation(issuer))
// {
// return issuer;
// }
// else
// {
// throw new SecurityTokenInvalidIssuerException("Invalid issuer");
// }
//}
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
}
}
);
}
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
var idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithClientSecret(appSecret)
.WithAuthority("https://login.microsoftonline.com/<your tenant id>")
.Build();
string message;
string debug;
try
{
string[] scopes = graphScopes.Split(' ');
var result = await idClient.AcquireTokenByAuthorizationCode(
scopes, notification.Code).ExecuteAsync();
message = "Access token retrieved.";
debug = result.AccessToken;
}
catch (MsalException ex)
{
message = "AcquireTokenByAuthorizationCodeAsync threw an exception";
debug = ex.Message;
}
var queryString = $"message={message}&debug={debug}";
if (queryString.Length > 2048)
{
queryString = queryString.Substring(0, 2040) + "...";
}
notification.HandleResponse();
notification.Response.Redirect($"/Home/Error?{queryString}");
}
private Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
string redirect = $"/Home/Error?message={notification.Exception.Message}";
if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
{
redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}";
}
notification.Response.Redirect(redirect);
return Task.FromResult(0);
}

How to create event with videoconference in Google Meet in C# using Google Calendar API?

Well.. I'm trying this code to create an Event
CalendarService service;
GoogleCredential credential;
try
{
string[] scopes = new string[] { CalendarService.Scope.Calendar };
using (var stream = new FileStream(#"C:\Prueba\meet.json", FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(scopes);
}
service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential
});
Event calendarEvent = new Event();
DateTime start = DateTime.Now;
calendarEvent.Kind = "";
calendarEvent.Summary = "prueba";
calendarEvent.Status = "confirmed";
calendarEvent.Visibility = "public";
calendarEvent.Description = "prueba";
calendarEvent.Creator = new Event.CreatorData
{
Email = "email#example.com", //email#example.com
Self = true
};
calendarEvent.Organizer = new Event.OrganizerData
{
Email = "email#example.com",
Self = true
};
calendarEvent.Start = new EventDateTime
{
DateTime = start,
TimeZone = "America/Mexico_City"
};
calendarEvent.End = new EventDateTime
{
DateTime = start.AddHours(1),
TimeZone = "America/Mexico_City"
};
calendarEvent.Recurrence = new String[] { "RRULE:FREQ=DAILY;COUNT=1" };
calendarEvent.Sequence = 0;
calendarEvent.HangoutLink = "";
calendarEvent.ConferenceData = new ConferenceData
{
CreateRequest = new CreateConferenceRequest
{
RequestId = "1234abcdef",
ConferenceSolutionKey = new ConferenceSolutionKey
{
Type = "hangoutsMeet"
},
Status = new ConferenceRequestStatus
{
StatusCode = "success"
}
},
EntryPoints = new List<EntryPoint>
{
new EntryPoint
{
EntryPointType = "video",
Uri = "",
Label = ""
}
},
ConferenceSolution = new ConferenceSolution
{
Key = new ConferenceSolutionKey
{
Type = "hangoutsMeet"
},
Name = "Google Meet",
IconUri = ""
},
ConferenceId = ""
};
//calendarEvent.EventType = "default";
EventsResource.InsertRequest request = service.Events.Insert(calendarEvent, "email#example.com");
request.ConferenceDataVersion = 0;
Event createEvent = request.Execute();
string url = createEvent.HangoutLink;
}
catch (Exception ex)
{
}
The source code is here
When I execute the line 116: Event createEvent = request.Execute();
I get this error: Google.Apis.Requests.RequestError Invalid conference type value. [400] Errors [Message[Invalid conference type value.] Location[ - ] Reason[invalid] Domain[global]
I don't know what means this error o with line I wrong
Could anyone help me with an example to create an event using classes C# from Google API Calendar?
As described in the C# library documentation for createRequest:
Either conferenceSolution and at least one entryPoint, or createRequest is required.
This means that you should use only CreateConferenceRequest as this conference is brand new (if it already existed then you would be wanting to use ConferenceSolution along with EntryPoints ). Therefore, simply remove ConferenceSolution and EntryPoints to leave just CreateConferenceRequest which as specified in the documentation is used for generating a new conference and attach it to the event.

Add role to already created application using Azure AD Graph API in C#

How to add roles in application that is already created on azure ad using Azure AD Graph API in c#.
I create role like this in c#:
Guid _id = new Guid();
AppRole appRole = new AppRole
{
AllowedMemberTypes = _AllowedMemberTypes,
Description = "Admins can manage roles and perform all actions.",
DisplayName = "Global Admin",
Id = _id,
IsEnabled = true,
Value = "Admin"
};
What call will be used to add this new role in application using Azure AD Graph API.
Finally i was able to create a new role on azure using Azure Ad Graph API
1) Create a Role:
Guid _id = Guid.NewGuid();
List<String> _AllowedMemberTypes = new List<string> {
"User"
};
AppRole appRole = new AppRole
{
AllowedMemberTypes = _AllowedMemberTypes,
Description = "Admins can manage roles and perform all actions.",
DisplayName = "Global Admin",
Id = _id,
IsEnabled = true,
Value = "Admin"
};
2) Get Application in which role needed to be created:
IPagedCollection<IApplication> pagedCollection = await activeDirectoryClient.Applications.Where(x => x.AppId == AppclientId).ExecuteAsync();
var appObject = pagedCollection.CurrentPage.ToList().FirstOrDefault();
3) Add Role to Applicationa and Update Application:
appObject.AppRoles.Add(appRole as AppRole);
await appObject.UpdateAsync();
You could refer to the code as below to assign application role.
1.get access token
private static async Task<string> GetAppTokenAsync(string graphResourceId, string tenantId, string clientId, string secretKey)
{
string aadInstance = "https://login.microsoftonline.com/" + tenantId + "/oauth2/token";
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance, false);
var result = await authenticationContext.AcquireTokenAsync(graphResourceId,
new ClientCredential(clientId, userId));
return result.AccessToken;
}
2.Init the graphclient.
var graphResourceId = "https://graph.windows.net";
var tenantId = "tenantId";
var clientId = "client Id";
var secretKey = "secret key";
var servicePointUri = new Uri(graphResourceId);
var serviceRoot = new Uri(servicePointUri, tenantId);
var activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await GetAppTokenAsync(graphResourceId, tenantId, clientId, secretKey));
3.create role
AppRole appRole = new AppRole
{
Id = Guid.NewGuid(),
IsEnabled = true,
Description = "Admins can manage roles and perform all actions.",
DisplayName = "Global Admin",
Value = "Admin"
};
4.add role assginments
User user = (User) activeDirectoryClient.Users.GetByObjectId("userobjectId").ExecuteAsync().Result;
AppRoleAssignment appRoleAssignment = new AppRoleAssignment
{
Id = appRole.Id,
ResourceId = Guid.Parse(newServicePrincpal.ObjectId),
PrincipalType = "User",
PrincipalId = Guid.Parse(user.ObjectId),
};
user.AppRoleAssignments.Add(appRoleAssignment);
user.UpdateAsync().Wait();

Token validation with IdentityServer3 + Entity Framework

I am using Identity Server 3 with Entity Framework. My ASP.NET MVC app logs in to the SSO/IdentityServer app using below configuration and then that access token is saved in a cookie which is used by javascript to call our API.
Problem is when I login to my ASP.NET MVC app then I go to database and delete that token from the database table, then my API says invalid bearer token as expected, but when I the refresh page in the ASP.NET MVC app, it still shows as logged in and I think it's because of cookie configuration.
How can I ask MVC app to always validate token from server?
AuthConfig.cs of ASP.NET MVC application:
public static class AuthConfig
{
public static void RegisterAuth(IAppBuilder app)
{
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => true;
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
SlidingExpiration = true,
ExpireTimeSpan = SellutionConstants.Globals.AccessTokenExpirationTimeSpan
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = "sellutionapp",
Authority = SsoConfigHelper.SellutionSts,
ResponseType = "code id_token",
Scope = "openid profile roles all_claims " + SsoConfigHelper.SellutionApiScope,
UseTokenLifetime = false,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role",
},
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
// use the code to get the access and refresh token
var tokenClient = new TokenClient(
SsoConfigHelper.SellutionStsTokenEndpoint,
"sellutionapp",
"secret");
if (String.IsNullOrEmpty(n.RedirectUri))
{
n.RedirectUri = n.Request.Scheme + "://" + n.Request.Host + n.Request.PathBase;
}
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
// use the access token to retrieve claims from userinfo
var userInfoClient = new UserInfoClient(
new Uri(SsoConfigHelper.SellutionStsUserInfoEndpoint),
tokenResponse.AccessToken);
var userInfoResponse = await userInfoClient.GetAsync();
// create new identity
var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
id.AddClaims(userInfoResponse.GetClaimsIdentity().Claims);
id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
//id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));
LoginCookieHelper.SetUserData(tokenResponse.AccessToken);
n.AuthenticationTicket = new AuthenticationTicket(
new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
// This ensures that the address used for sign in and sign out is picked up dynamically from the request
// this allows you to deploy the app (to Azure Web Sites, for example) without having to change settings.
var appBaseUrl = n.Request.Scheme + "://" + n.Request.Host + n.Request.PathBase;
n.ProtocolMessage.RedirectUri = appBaseUrl;
n.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
}
});
}
}
Identity server configuration:
class Factory
{
public static IdentityServerServiceFactory Configure()
{
var efConfig = new EntityFrameworkServiceOptions
{
ConnectionString = "DefaultConnection",
};
// these two calls just pre-populate the test DB from the in-memory config
ConfigureClients(Clients.Get(), efConfig);
ConfigureScopes(Scopes.Get(), efConfig);
var factory = new IdentityServerServiceFactory();
//var scopeStore = new InMemoryScopeStore(Scopes.Get());
//factory.ScopeStore = new Registration<IScopeStore>(scopeStore);
//var clientStore = new InMemoryClientStore(Clients.Get());
//factory.ClientStore = new Registration<IClientStore>(clientStore);
factory.CorsPolicyService = new Registration<ICorsPolicyService>(new DefaultCorsPolicyService { AllowAll = true });
factory.RegisterOperationalServices(efConfig);
factory.RegisterConfigurationServices(efConfig);
return factory;
}
public static void ConfigureClients(IEnumerable<Client> clients, EntityFrameworkServiceOptions options)
{
using (var db = new ClientConfigurationDbContext(options.ConnectionString, options.Schema))
{
if (!db.Clients.Any())
{
foreach (var c in clients)
{
var e = c.ToEntity();
db.Clients.Add(e);
}
db.SaveChanges();
}
}
}
public static void ConfigureScopes(IEnumerable<Scope> scopes, EntityFrameworkServiceOptions options)
{
using (var db = new ScopeConfigurationDbContext(options.ConnectionString, options.Schema))
{
if (!db.Scopes.Any())
{
foreach (var s in scopes)
{
var e = s.ToEntity();
db.Scopes.Add(e);
}
db.SaveChanges();
}
}
}
}
IdentityServer client configuration
public class Clients
{
public static List<Client> Get()
{
return new List<Client>
{
new Client
{
ClientName = "Resource Owner Flow",
ClientId = "resourceowner",
ClientSecrets = new List<Secret> {new Secret("vkgk8M4pj".Sha256())},
Flow = Flows.ResourceOwner , //Password authentication
PrefixClientClaims = false,
AccessTokenType = AccessTokenType.Jwt,
AllowedScopes = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
Constants.StandardScopes.Roles,
Constants.StandardScopes.Address,
Constants.StandardScopes.AllClaims,
Constants.StandardScopes.OfflineAccess,
SsoConfigHelper.SellutionApiScope
},
RequireConsent = false,
AllowRememberConsent = true,
LogoutSessionRequired = true,
RefreshTokenExpiration = TokenExpiration.Absolute,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
UpdateAccessTokenClaimsOnRefresh = true,
AbsoluteRefreshTokenLifetime =(int)TimeSpan.FromDays(1).TotalSeconds
},
/////////////////////////////////////////////////////////////
// MVC OWIN Implicit Client
/////////////////////////////////////////////////////////////
new Client
{
ClientName = "Sellution Application",
ClientId = "sellutionapp",
Flow = Flows.Hybrid,
AllowAccessTokensViaBrowser = false,
AllowedScopes = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
Constants.StandardScopes.Roles,
Constants.StandardScopes.Address,
Constants.StandardScopes.AllClaims,
SsoConfigHelper.SellutionApiScope
},
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
AccessTokenType = AccessTokenType.Reference,
RequireConsent = false,
AllowRememberConsent = true,
LogoutSessionRequired = true,
},
};
}
}
You need to sign the user out of the MVC application as well because according to your code you are using Cookie Authentication named Cookies you also have to do a sign out on that authentication scheme when they log out (not deleteing the token in the store).
AuthenticationManager.SignOut("Cookies"); is what your controller action will require for logout.

Categories

Resources