/// <summary> /// Adds the user access token handler to an HttpClient /// </summary> /// <param name="httpClientBuilder"></param> /// <param name="parameters"></param> /// <returns></returns> public static IHttpClientBuilder AddUserAccessTokenHandler(this IHttpClientBuilder httpClientBuilder, UserAccessTokenParameters parameters = null) { return(httpClientBuilder.AddHttpMessageHandler(provider => { var contextAccessor = provider.GetRequiredService <IHttpContextAccessor>(); return new UserAccessTokenHandler(contextAccessor, parameters); })); }
/// <summary> /// Revokes the current user refresh token /// </summary> /// <param name="httpContext">The HTTP context</param> /// <param name="parameters">Extra optional parameters</param> /// <param name="cancellationToken">A cancellation token to cancel operation.</param> /// <returns></returns> public static async Task RevokeUserRefreshTokenAsync( this HttpContext httpContext, UserAccessTokenParameters parameters = null, CancellationToken cancellationToken = default) { var service = httpContext.RequestServices.GetRequiredService<IUserAccessTokenManagementService>(); var store = httpContext.RequestServices.GetRequiredService<IUserTokenStore>(); await service.RevokeRefreshTokenAsync(httpContext.User, parameters, cancellationToken); await store.ClearTokenAsync(httpContext.User); }
/// <summary> /// Adds a named HTTP client for the factory that automatically sends the current user access token /// </summary> /// <param name="services"></param> /// <param name="name">The name of the client.</param> /// <param name="parameters"></param> /// <param name="configureClient">Additional configuration.</param> /// <returns></returns> public static IHttpClientBuilder AddUserAccessTokenHttpClient(this IServiceCollection services, string name, UserAccessTokenParameters parameters = null, Action <HttpClient> configureClient = null) { if (configureClient != null) { return(services.AddHttpClient(name, configureClient) .AddUserAccessTokenHandler(parameters)); } return(services.AddHttpClient(name) .AddUserAccessTokenHandler(parameters)); }
/// <summary> /// Endpoint logic /// </summary> /// <param name="localPath">The local path (e.g. /api)</param> /// <param name="apiAddress">The remote address (e.g. https://api.myapp.com/foo)</param> /// <returns></returns> /// <exception cref="InvalidOperationException"></exception> public static RequestDelegate Map(string localPath, string apiAddress) { return(async context => { var loggerFactory = context.RequestServices.GetRequiredService <ILoggerFactory>(); var logger = loggerFactory.CreateLogger(LogCategories.RemoteApiEndpoints); var endpoint = context.GetEndpoint(); if (endpoint == null) { throw new InvalidOperationException("endpoint not found"); } var metadata = endpoint.Metadata.GetMetadata <BffRemoteApiEndpointMetadata>(); if (metadata == null) { throw new InvalidOperationException("API endoint is missing BFF metadata"); } UserAccessTokenParameters toUserAccessTokenParameters = null; if (metadata.BffUserAccessTokenParameters != null) { toUserAccessTokenParameters = metadata.BffUserAccessTokenParameters.ToUserAccessTokenParameters(); } string token = null; if (metadata.RequiredTokenType.HasValue) { token = await context.GetManagedAccessToken(metadata.RequiredTokenType.Value, toUserAccessTokenParameters); if (string.IsNullOrWhiteSpace(token)) { logger.AccessTokenMissing(localPath, metadata.RequiredTokenType.Value); context.Response.StatusCode = 401; return; } } if (token == null) { if (metadata.OptionalUserToken) { token = await context.GetUserAccessTokenAsync(toUserAccessTokenParameters); } } var forwarder = context.RequestServices.GetRequiredService <IHttpForwarder>(); var clientFactory = context.RequestServices.GetRequiredService <IHttpMessageInvokerFactory>(); var transformerFactory = context.RequestServices.GetRequiredService <IHttpTransformerFactory>(); var httpClient = clientFactory.CreateClient(localPath); var transformer = transformerFactory.CreateTransformer(localPath, token); await forwarder.SendAsync(context, apiAddress, httpClient, ForwarderRequestConfig.Empty, transformer); var errorFeature = context.Features.Get <IForwarderErrorFeature>(); if (errorFeature != null) { var error = errorFeature.Error; var exception = errorFeature.Exception; logger.ProxyResponseError(localPath, exception?.ToString() ?? error.ToString()); } }); }
public static async Task <string> GetManagedAccessToken(this HttpContext context, TokenType tokenType, UserAccessTokenParameters userAccessTokenParameters = null) { string token; if (tokenType == TokenType.User) { token = await context.GetUserAccessTokenAsync(userAccessTokenParameters); } else if (tokenType == TokenType.Client) { token = await context.GetClientAccessTokenAsync(); } else { token = await context.GetUserAccessTokenAsync(userAccessTokenParameters); if (string.IsNullOrEmpty(token)) { token = await context.GetClientAccessTokenAsync(); } } return(token); }
/// <summary> /// Returns (and refreshes if needed) the current access token for the logged on user /// </summary> /// <param name="httpContext">The HTTP context</param> /// <param name="parameters">Extra optional parameters</param> /// <param name="cancellationToken">A cancellation token to cancel operation.</param> /// <returns></returns> public static async Task<string> GetUserAccessTokenAsync(this HttpContext httpContext, UserAccessTokenParameters parameters = null, CancellationToken cancellationToken = default) { // todo convert null exception to TaskCanceledException for blazor. if (httpContext == null) { throw new TaskCanceledException(); } try { var service = httpContext.RequestServices.GetRequiredService<IUserAccessTokenManagementService>(); return await service.GetUserAccessTokenAsync(httpContext.User, parameters, cancellationToken); } catch (NullReferenceException) { throw new TaskCanceledException(); } }
/// <summary> /// Returns (and refreshes if needed) the current access token for the logged on user /// </summary> /// <param name="httpContext">The HTTP context</param> /// <param name="parameters">Extra optional parameters</param> /// <param name="cancellationToken">A cancellation token to cancel operation.</param> /// <returns></returns> public static async Task <string> GetUserAccessTokenAsync(this HttpContext httpContext, UserAccessTokenParameters parameters = null, CancellationToken cancellationToken = default) { var service = httpContext.RequestServices.GetRequiredService <IUserAccessTokenManagementService>(); return(await service.GetUserAccessTokenAsync(httpContext.User, parameters, cancellationToken)); }