/// <summary> /// Get the stored tokens associated with the http context. /// </summary> /// <param name="context">The current http context.</param> /// <param name="authority">The authority of the OIDC configuration.</param> /// <param name="clientId">The OIDC client id of this application.</param> /// <param name="clientSecret">The OIDC client secret of this application.</param> /// <param name="resource">The OIDC resource identifier.</param> /// <returns>A tuple with the id and access tokens.</returns> public static async Task <(string idToken, string accessToken)> GetTokensFromContext( HttpContext context, string authority, string clientId, string clientSecret, string resource ) { var authContext = new AuthenticationContext(authority, AuthPropertiesTokenCache.ForApiCalls(context, CookieAuthenticationDefaults.AuthenticationScheme)); var credential = new ClientCredential(clientId, clientSecret); var userObjectId = context.User.FindFirst(ObjectIdentifierClaimUri).Value; var result = await authContext.AcquireTokenSilentAsync( resource : resource, clientCredential : credential, userId : new UserIdentifier(userObjectId, UserIdentifierType.UniqueId) ); return( idToken : result.IdToken, accessToken : result.AccessToken ); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.Configure <CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { Configuration.Bind("OpenId", options); // We need the authorization code to get both id and access tokens options.ResponseType = "code id_token"; // Saves the access token in the cookies options.SaveTokens = true; // Session lifetime will match the tokens' options.UseTokenLifetime = true; // WorkflowGen's GraphQL API doesn't have a /userinfo endpoint // like described in the OpenID Connect protocol. This prevents // the middleware from requesting from this endpoint. options.GetClaimsFromUserInfoEndpoint = false; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = "role" }; // Adds an action to map custom claims from additional scopes. options.ClaimActions.MapUniqueJsonKey("sub", "sub"); options.ClaimActions.MapUniqueJsonKey("name", "name"); options.ClaimActions.MapUniqueJsonKey("given_name", "given_name"); options.ClaimActions.MapUniqueJsonKey("family_name", "family_name"); options.ClaimActions.MapUniqueJsonKey("profile", "profile"); options.ClaimActions.MapUniqueJsonKey("email", "email"); // Ensures that only the following scopes are requested. // If you need more, add them here. options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("email"); options.Events = new OpenIdConnectEvents { // Manually handles the exchange of the authorization code // for tokens (id token and access token) OnAuthorizationCodeReceived = async context => { var request = context.HttpContext.Request; var currentUri = UriHelper.BuildAbsolute( scheme: request.Scheme, host: request.Host, pathBase: request.PathBase, path: request.Path ); var credential = new ClientCredential(options.ClientId, options.ClientSecret); var authContext = new AuthenticationContext( options.Authority, tokenCache: AuthPropertiesTokenCache.ForCodeRedemption(context.Properties) ); var result = await authContext.AcquireTokenByAuthorizationCodeAsync( authorizationCode: context.ProtocolMessage.Code, redirectUri: new Uri(currentUri), credential, resource: options.Resource ); context.HandleCodeRedemption(result.AccessToken, result.IdToken); } }; }); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddTransient <IGraphQLClient, GraphQLHttpClient>(provider => { // Retrieve the access token from the TokenCache. var httpContextAccessor = provider.GetService <IHttpContextAccessor>(); var client = new GraphQLHttpClient(Configuration["OpenId:Resource"]); (var _, var accessToken) = Utilities.GetTokensFromContext( context: httpContextAccessor.HttpContext, authority: Configuration["OpenId:Authority"], clientId: Configuration["OpenId:ClientId"], clientSecret: Configuration["OpenId:ClientSecret"], resource: Configuration["OpenId:Resource"] ).Result; client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}"); return(client); }); services.AddMvc(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }