Compare commits
6 commits
bb4ad4fcb8
...
c354cbab78
| Author | SHA1 | Date | |
|---|---|---|---|
| c354cbab78 | |||
| b1e8d37f21 | |||
| 1b0933c215 | |||
| 6e4b68c60d | |||
| 7fa55a68c9 | |||
| f3bb039d2f |
16 changed files with 153 additions and 111 deletions
22
contrib/bruno/blog post.yml
Normal file
22
contrib/bruno/blog post.yml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
info:
|
||||
name: blog post
|
||||
type: http
|
||||
seq: 2
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: "{{Blogs}}/api/v1/blog"
|
||||
body:
|
||||
type: json
|
||||
data: |-
|
||||
{
|
||||
"Title": "lkijlk",
|
||||
"Article": "test"
|
||||
}
|
||||
auth: inherit
|
||||
|
||||
settings:
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
followRedirects: true
|
||||
maxRedirects: 5
|
||||
|
|
@ -25,7 +25,7 @@ request:
|
|||
credentials:
|
||||
clientId: postit
|
||||
placement: basic_auth_header
|
||||
scope: openid blogs
|
||||
scope: openid blogs profile
|
||||
pkce: {}
|
||||
tokenConfig:
|
||||
id: credentials
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ namespace Yavsc
|
|||
|
||||
public const string StreamingPath = "/api/stream/put";
|
||||
|
||||
public static string NameClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/name";
|
||||
|
||||
public static string RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace Yavsc.Abstract.Identity
|
|||
/// </remarks>
|
||||
public static string AvatarSrc(IApplicationUser? user)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(user?.UserName))
|
||||
if (user==null || string.IsNullOrWhiteSpace(user?.UserName))
|
||||
return YavscConstants.DefaultAvatar;
|
||||
return $"{YavscConstants.AvatarsPath}/{user!.UserName}.s.png";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ namespace Yavsc.Blogs.Controllers
|
|||
return new StatusCodeResult(StatusCodes.Status204NoContent);
|
||||
}
|
||||
|
||||
// POST: api/BlogApi
|
||||
// POST: api/v1/blog
|
||||
[HttpPost]
|
||||
public IActionResult PostBlog([FromBody] Models.Blog.BlogPost blog)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,22 +37,16 @@ internal class Program
|
|||
.AddYavscCors(builder.Configuration)
|
||||
.AddControllers();
|
||||
String authority = builder.Configuration.GetValue<string>("Site:Authority");
|
||||
String audience = builder.Configuration.GetValue<string>("Site:Audience");
|
||||
|
||||
if (string.IsNullOrEmpty(authority))
|
||||
{
|
||||
throw new Exception("Site:Authority is not configured in appsettings.json");
|
||||
}
|
||||
|
||||
|
||||
// AuthenticationBuilder
|
||||
services.AddAuthentication("Bearer")
|
||||
.AddYavscJwtBearer(builder.Configuration,
|
||||
options =>
|
||||
{
|
||||
options.Authority = authority;
|
||||
options.Audience = builder.Configuration.GetValue<string>
|
||||
("Site:Audience");
|
||||
});
|
||||
.AddYavscJwtBearer(builder.Configuration);
|
||||
|
||||
|
||||
// DbContextBuilder
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
|
|
@ -100,7 +94,7 @@ internal class Program
|
|||
.UseCors("default")
|
||||
;
|
||||
app.Services.GetRequiredService<ILoggerFactory>().CreateLogger("Program")
|
||||
.LogInformation($"Yavsc.Blogs started, Authority is '{authority}', Audience is '{audience}'");
|
||||
.LogInformation($"Yavsc.Blogs started, Authority is '{authority}''");
|
||||
app.MapControllers();
|
||||
app.MapIdentityApi<ApplicationUser>().RequireAuthorization("BlogScope")
|
||||
.WithHttpLogging(Microsoft.AspNetCore.HttpLogging.HttpLoggingFields.All)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
"Description": "A collection of blogs about software development, technology, and programming.",
|
||||
"Keywords": "software development, technology, programming, coding, blogs",
|
||||
"Authority": "https://localhost:5001",
|
||||
"Audience": ["blogs"],
|
||||
"CorsAllowedOrigins": [
|
||||
"https://localhost:5005"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -8,32 +8,32 @@ namespace Yavsc.Org.Tests
|
|||
[Trait("regression", "oui")]
|
||||
public class Remoting : BaseTestContext, IClassFixture<WebServerFixture>
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public Remoting(WebServerFixture serverFixture, ITestOutputHelper output)
|
||||
: base(output, serverFixture)
|
||||
{
|
||||
|
||||
_output = output;
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task ObtainServiceToken()
|
||||
{
|
||||
var serverUrl = _serverFixture.SiteSettings.Authority;
|
||||
if (string.IsNullOrEmpty(serverUrl))
|
||||
throw new InvalidOperationException("No HTTPS server address found");
|
||||
var serverUrl = GetServerUrl();
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
|
||||
HttpClient client = NewHttpClient();
|
||||
var disco = await client.GetDiscoveryDocumentAsync(serverUrl);
|
||||
if (disco.IsError) throw new Exception(disco.Error);
|
||||
var tokenEndpoint = await ResolveTokenEndpointAsync(client, serverUrl, cancellationToken);
|
||||
|
||||
var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
|
||||
{
|
||||
Address = disco.TokenEndpoint,
|
||||
ClientId = _serverFixture.TestClientId,
|
||||
ClientSecret = _serverFixture.TestClientSecret,
|
||||
Address = tokenEndpoint,
|
||||
ClientId = RequireNonEmpty(_serverFixture.TestClientId, nameof(_serverFixture.TestClientId)),
|
||||
ClientSecret = RequireNonEmpty(_serverFixture.TestClientSecret, nameof(_serverFixture.TestClientSecret)),
|
||||
Scope = "test",
|
||||
GrantType = "client_credentials"
|
||||
});
|
||||
}, cancellationToken);
|
||||
if (response.IsError) throw new Exception(response.Error);
|
||||
}
|
||||
|
||||
|
|
@ -45,27 +45,25 @@ namespace Yavsc.Org.Tests
|
|||
[Fact]
|
||||
public async Task ObtainResourceOwnerPasswordToken()
|
||||
{
|
||||
var serverUrl = _serverFixture.SiteSettings.Authority;
|
||||
if (string.IsNullOrEmpty(serverUrl))
|
||||
throw new InvalidOperationException("No HTTPS server address found");
|
||||
var serverUrl = GetServerUrl();
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
|
||||
var client = NewHttpClient();
|
||||
var disco = await client.GetDiscoveryDocumentAsync(serverUrl);
|
||||
if (disco.IsError) throw new Exception(disco.Error);
|
||||
var tokenEndpoint = await ResolveTokenEndpointAsync(client, serverUrl, cancellationToken);
|
||||
|
||||
var response = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
|
||||
{
|
||||
Address = disco.TokenEndpoint,
|
||||
ClientId = _serverFixture.TestClientId,
|
||||
ClientSecret = _serverFixture.TestClientSecret,
|
||||
UserName = _serverFixture.TestingUserName,
|
||||
Password = _serverFixture.TestingUserPassword,
|
||||
Address = tokenEndpoint,
|
||||
ClientId = RequireNonEmpty(_serverFixture.TestClientId, nameof(_serverFixture.TestClientId)),
|
||||
ClientSecret = RequireNonEmpty(_serverFixture.TestClientSecret, nameof(_serverFixture.TestClientSecret)),
|
||||
UserName = RequireNonEmpty(_serverFixture.TestingUserName, nameof(_serverFixture.TestingUserName)),
|
||||
Password = RequireNonEmpty(_serverFixture.TestingUserPassword, nameof(_serverFixture.TestingUserPassword)),
|
||||
Scope = "test",
|
||||
Parameters =
|
||||
{
|
||||
{ "acr_values", "tenant:custom_account_store1 foo bar quux" }
|
||||
}
|
||||
});
|
||||
}, cancellationToken);
|
||||
|
||||
if (response.IsError) throw new Exception(response.Error);
|
||||
|
||||
|
|
@ -76,6 +74,36 @@ namespace Yavsc.Org.Tests
|
|||
return new object[][] { new object[] { "testuser", "test" } };
|
||||
}
|
||||
|
||||
private async Task<string> ResolveTokenEndpointAsync(HttpClient client, string serverUrl, CancellationToken cancellationToken)
|
||||
{
|
||||
var disco = await client.GetDiscoveryDocumentAsync(serverUrl, cancellationToken);
|
||||
if (!disco.IsError && !string.IsNullOrWhiteSpace(disco.TokenEndpoint))
|
||||
{
|
||||
return disco.TokenEndpoint;
|
||||
}
|
||||
|
||||
// Some full-suite runs intermittently return 500 on the OIDC
|
||||
// discovery document while /connect/token remains available.
|
||||
var fallback = new Uri(new Uri(serverUrl), "/connect/token").ToString();
|
||||
_output.WriteLine($"WARNING: OIDC discovery failed ({disco.Error}). Fallback token endpoint: {fallback}");
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private string GetServerUrl()
|
||||
{
|
||||
return RequireNonEmpty(_serverFixture.SiteSettings?.Authority, "SiteSettings.Authority");
|
||||
}
|
||||
|
||||
private static string RequireNonEmpty(string? value, string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new InvalidOperationException($"Missing required test setting: {name}");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class BypassSslValidationHandler : HttpClientHandler
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ using Yavsc.Server.Helpers;
|
|||
|
||||
// For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
namespace Yavsc.Org.Controllers
|
||||
{
|
||||
public class BlogSpotController : Controller
|
||||
{
|
||||
|
|
@ -28,7 +28,7 @@ namespace Yavsc.Controllers
|
|||
BlogSpotService blogSpotService)
|
||||
{
|
||||
_context = context;
|
||||
_logger = loggerFactory.CreateLogger<AccountController>();
|
||||
_logger = loggerFactory.CreateLogger<BlogSpotController>();
|
||||
_authorizationService = authorizationService;
|
||||
_localisationOptions = localisationOptions.Value;
|
||||
this.blogSpotService = blogSpotService;
|
||||
|
|
@ -76,7 +76,7 @@ namespace Yavsc.Controllers
|
|||
return View(blog);
|
||||
|
||||
}
|
||||
catch (AuthorizationFailureException ex)
|
||||
catch (AuthorizationFailureException)
|
||||
{
|
||||
return Challenge();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,8 +157,7 @@ public static class HostingExtensions
|
|||
|
||||
|
||||
services.AddAuthentication("Bearer")
|
||||
.AddYavscJwtBearer(builder.Configuration,
|
||||
configure: o => o.Audience = builder.Configuration.GetSection("Site")["ExternalUrl"]);
|
||||
.AddYavscJwtBearer(builder.Configuration);
|
||||
|
||||
services.AddTransient<RoleManager<IdentityRole>>();
|
||||
services.AddTransient<IRoleStore<IdentityRole>, RoleStore<IdentityRole, ApplicationDbContext>>();
|
||||
|
|
|
|||
|
|
@ -1,26 +1,24 @@
|
|||
using System.Diagnostics;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.DotNet.Scaffolding.Shared;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Server.Exceptions;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.Services;
|
||||
using Yavsc.ViewModels.Auth;
|
||||
using Yavsc.Abstract.Helpers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
public class BlogSpotService
|
||||
|
||||
[Obsolete]
|
||||
public class OldBlogSpotService
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IFileSystemAuthManager fileSystemAuthManager;
|
||||
|
||||
public BlogSpotService(ApplicationDbContext context,
|
||||
public OldBlogSpotService(ApplicationDbContext context,
|
||||
IAuthorizationService authorizationService,
|
||||
IFileSystemAuthManager fileSystemAuthManager)
|
||||
{
|
||||
|
|
@ -93,13 +91,13 @@ public class BlogSpotService
|
|||
public async Task<BlogPostEditViewModel> GetPostForEdition(ClaimsPrincipal user, long blogPostId)
|
||||
{
|
||||
var blog = await _context.BlogSpot.Include(x => x.Author).Include(x => x.ACL).SingleAsync(m => m.Id == blogPostId);
|
||||
var auth = await _authorizationService.AuthorizeAsync(user, blog, new EditPermission());
|
||||
var auth = await _authorizationService.AuthorizeAsync(user, blog, new EditPermission());
|
||||
if (!auth.Succeeded)
|
||||
{
|
||||
throw new AuthorizationFailureException(auth);
|
||||
}
|
||||
}
|
||||
var pub = await _context.blogSpotPublications.AnyAsync(x => x.BlogpostId == blog.Id);
|
||||
|
||||
|
||||
return new BlogPostEditViewModel(blog, pub);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
@using Yavsc.Abstract.Identity
|
||||
@model ApplicationUser
|
||||
@{
|
||||
// Le helper défend contre Model null et contre UserName vide
|
||||
// ou whitespace. Sans cette garde, Razor lève
|
||||
// NullReferenceException ici, ce qui propage un 500 et
|
||||
// masque aussi la page d'erreur.
|
||||
var avuri = UserDisplayHelpers.AvatarSrc(Model);
|
||||
}
|
||||
|
||||
<div class="userinfo">
|
||||
<a title="Posts" asp-controller="Blogspot" asp-action="Index" asp-route-id="@Model.UserName" class="btn btn-primary">
|
||||
@if (Model != null && !string.IsNullOrWhiteSpace(Model.UserName))
|
||||
{
|
||||
string avuri = UserDisplayHelpers.AvatarSrc(Model);
|
||||
|
||||
<a title="Posts" asp-controller="Blogspot" asp-action="Index" asp-route-id="@Model.UserName" class="btn btn-primary">
|
||||
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName" />
|
||||
</a>
|
||||
|
||||
} else {
|
||||
<div class="alert alert-warning">
|
||||
<strong>Utilisateur inconnu</strong>
|
||||
<img src="@YavscConstants.DefaultAvatar" class="smalltofhol" alt="Utilisateur inconnu" title="Utilisateur inconnu" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -74,48 +74,59 @@ public static class ServiceExtensions
|
|||
public static AuthenticationBuilder AddYavscJwtBearer(
|
||||
this AuthenticationBuilder builder,
|
||||
IConfiguration configuration,
|
||||
Action<JwtBearerOptions>? configure = null,
|
||||
string schemeName = "Bearer")
|
||||
{
|
||||
var authority = configuration.GetSection("Site")["Authority"]
|
||||
?? throw new InvalidOperationException(
|
||||
"Site:Authority is required to configure Yavsc JWT Bearer authentication.");
|
||||
|
||||
return builder.AddJwtBearer(schemeName, options =>
|
||||
{
|
||||
options.IncludeErrorDetails = true;
|
||||
options.Authority = authority;
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateAudience = false,
|
||||
RoleClaimType = YavscConstants.RoleClaimType
|
||||
};
|
||||
options.MapInboundClaims = true;
|
||||
|
||||
// Dev: every Yavsc resource service (Yavsc.Api, Yavsc.Blogs,
|
||||
// Yavsc.Org itself) validates JWTs against the OP that runs
|
||||
// on https://localhost:5001 with a self-signed dev cert.
|
||||
// The default .NET HttpClient rejects self-signed certs, so
|
||||
// JwtBearer's backchannel silently fails to fetch the OIDC
|
||||
// discovery + JWKS. With an empty ValidIssuer, every token
|
||||
// is rejected with IDX10204 ("ValidIssuer is null or
|
||||
// whitespace"). Telling the backchannel to skip TLS
|
||||
// validation unblocks discovery in dev. Production uses a
|
||||
// real CA-signed cert and the default validation path; the
|
||||
// override is gated on HostingEnvironment == Development
|
||||
// and only fires when the consumer opt-in via the
|
||||
// 'Yavsc:Dev:TlsInsecure' configuration flag (default
|
||||
// false), so a misconfigured production environment cannot
|
||||
// silently downgrade TLS.
|
||||
if (configuration.GetValue<string>("ASPNETCORE_ENVIRONMENT") == "Development")
|
||||
string[] audiences = configuration.GetSection("Site").GetSection("Audience").Get<string[]>() ?? Array.Empty<string>();
|
||||
AuthenticationBuilder result = builder;
|
||||
foreach (var audience in audiences)
|
||||
{
|
||||
result = builder.AddJwtBearer(schemeName, options =>
|
||||
{
|
||||
options.BackchannelHttpHandler = new HttpClientHandler
|
||||
options.IncludeErrorDetails = true;
|
||||
options.Authority = authority;
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ServerCertificateCustomValidationCallback =
|
||||
(_, _, _, _) => true
|
||||
ValidateAudience = true,
|
||||
ValidAudience = audience,
|
||||
RoleClaimType = YavscConstants.RoleClaimType,
|
||||
NameClaimType = YavscConstants.NameClaimType,
|
||||
};
|
||||
}
|
||||
configure?.Invoke(options);
|
||||
});
|
||||
options.MapInboundClaims = true;
|
||||
options.ClaimsIssuer = authority;
|
||||
options.Audience = audience;
|
||||
|
||||
// Dev: every Yavsc resource service (Yavsc.Api, Yavsc.Blogs,
|
||||
// Yavsc.Org itself) validates JWTs against the OP that runs
|
||||
// on https://localhost:5001 with a self-signed dev cert.
|
||||
// The default .NET HttpClient rejects self-signed certs, so
|
||||
// JwtBearer's backchannel silently fails to fetch the OIDC
|
||||
// discovery + JWKS. With an empty ValidIssuer, every token
|
||||
// is rejected with IDX10204 ("ValidIssuer is null or
|
||||
// whitespace"). Telling the backchannel to skip TLS
|
||||
// validation unblocks discovery in dev. Production uses a
|
||||
// real CA-signed cert and the default validation path; the
|
||||
// override is gated on HostingEnvironment == Development
|
||||
// and only fires when the consumer opt-in via the
|
||||
// 'Yavsc:Dev:TlsInsecure' configuration flag (default
|
||||
// false), so a misconfigured production environment cannot
|
||||
// silently downgrade TLS.
|
||||
if (configuration.GetValue<string>("ASPNETCORE_ENVIRONMENT") == "Development")
|
||||
{
|
||||
options.BackchannelHttpHandler = new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback =
|
||||
(_, _, _, _) => true
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace Yavsc.Server.Helpers
|
|||
(x.ACL.Count == 0 || x.ACL.Any(a => readerCirclesMemberships.Contains(a.CircleId))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static string GetUserId(this ClaimsPrincipal user)
|
||||
{
|
||||
return user.FindFirstValue("sub");
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace cli
|
|||
public string ClientId { get; set; }
|
||||
public string ClientSecret { get; set; }
|
||||
public string Authority { get; set; }
|
||||
public string Audience { get; set; }
|
||||
public string[] Audience { get; set; }
|
||||
public string SiteAccessSheme { get; set; } = "http";
|
||||
public int Port { get; set; }
|
||||
public string Scope { get; set; } = "profile";
|
||||
|
|
@ -21,14 +21,14 @@ namespace cli
|
|||
return Port==0 ? $"{SiteAccessSheme}://{Authority}/authorize" :
|
||||
$"{SiteAccessSheme}://{Authority}:{Port}/authorize" ;
|
||||
} }
|
||||
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public string RedirectUrl {get {
|
||||
return Port==0 ? $"{SiteAccessSheme}://{Authority}/oauth/success" :
|
||||
$"{SiteAccessSheme}://{Authority}:{Port}/oauth/success" ;
|
||||
} }
|
||||
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public string AccessTokenUrl { get {
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"UserConnection": {
|
||||
"UserName": "Paul",
|
||||
"AccessToken": "IvvrnJye2b7CSFp2Hj3mEEK1-7EMbLLGJATQHAwOlRt5sIcm9aMH85kJMAxDb4yIzL76G7maoIlaWuSyhhS3qfcIB04WcVnCVdmw22ncMs8rk_L0yGuLdNBnF3HuhZXpjD-AjpLJ1TdE0q3c-yakkP_EWTjM9I00a1gGop4bgE_-LAa2uoLeaCj0dbe95OSvVKJWJ4MU0fjlvqAaUx-EC4HYicUMEQvJviR0FyyMKPYYyx4jyu_bgYbhmKX9LoE5VeEDEMsyXZE0fxqdfnflICduUqrprCvQfLoG4DZ8o7ivjoak3-xiP7CFaF1vou89mO1c9BcJYUjcZXPgNYC7K9QHwFC5sPDkOHdijUo9xfieRaaqge5tEHlZAs3H_u-bGWft7xjxHOVUPSRzzYygR27alVSUIt6rt28FoLsEGYQaVK5QNzIbOE0RVU40vQb5a6JzcTcjTtRxCMn3FneKZtilEHb2TooUy4YbmhbnDIKsa0ZMMBEshyEel8oCWz9SITjm24FbdCmUvSKOlkHhIcnSM8oez9qhDlzzcsKzahbNeO-EBINW-6qBlKISQbFmfy-zO134JEkcpfA9NybGcYPZWLWu1IrF9pDzO66X2Rh-H45pHQWRWFodHcoQh0p9ZBNwo5k_EkU731uwQZF5zgGyZnUU2VpxdjorzrpexZXpStzYnYRbGGK7kGAUZH9v16zL-nB4t55Mu12iK9jsUIS7cmqOSTj4mJWFd03dwe4xkNrLgcGSGPebmsfSWYaIk7qAmWMsPKKv_vnOpi-1sZuOgdVyH-RmuyW83IPCUiEAf63a40PuqpVxFiMmbcRqSKvh5TedjWUiEZvBvz786-atYF_b0dxCj8fDQbyWiMj-4Lj7FV4gUJFvrDX4DsRns6wL6Cs3urL4PmKHLEhRma-i589pEKmzinO7l4S2atB6uqMS_xNU7Y0um_GQ51oPk8PxxCggI2aLR4PJbuBGSJBoTDW1OV9HNa_BybrKamN8cuc8IT3LBJiHH_ImHyW1n94C2oFcaUJ1dVVt6JDJqt4EVvFiwk15SlRJMXSLWQWxPKeOTCGb-So2Gcy_DwGu8_AlVL4mOdQI0GiGRkpaWNIF3N6ek-B_7Lz1zxKX7BCx1ISurAzG7jK1FDydovJ2LOHO6QbqVH1JKRdRDCLOKZl3TpcAyOQHDo5rAl84pwf5UROMb5SfVDJtdekb7SRR",
|
||||
"TokenType": "bearer",
|
||||
"ExpiresIn": "1199",
|
||||
"RefreshToken": "CfDJ8LSG6cXzxTtFuur3SY2RDINpvQVezgrIru8TEIfKUpNmUXe5lA4tCQ_nlkklgarH5UocJ6b95NLRon0uvVy5mE-7EY3ld_-bjLgjDnV9oPxY7Xdgb94_5HdDWcyG_Zaw67T0G_t21bvNEgtw0zewbdisPpjKopfH7avQWxlRrMbN9Wboj2ZXYVCbmu2EkeyG5665-B16UEQFF7dVT6qU4qnSldIfhx5ex8Ii5aGg0pDAEnRUNla_iObls2yAf18bmTAfF-34kmClqqLCr7z4Cy65DwQ8EHNA9oIEvgCEuj04IG5wC79vycZrw0NLQWAz7fTahRreD_WsmbIKdUqkvlDjV1W3Dq7KUCi4bAk7oAJuqdl3qZg4SohmQ31IKD08aKSOPa4_jtJ-eKOlT6fdDhpoaP3DyKS09OkvAwbMA86937IrCCFZsGBhHAm-yszHXjVjPCr7gAJYaBjneAUAoseEYK0GaOVGXfhxQcURXtM9TyH3pgHjccOzq300Djv-BpfQZcSZnQf59kulL_gt--451r8UIw3wxQ6BD5fGVF_MrilUluLyhoqoGZJbiHFyL-miKjW7feGFuogVyee0nIO1Me-7T-aTQnn-LivP9avyHab4eGwg1nfUbEspA21vmz2UXkUvKvT-JRGmSxlYineeJURQMcGGbcvr9GbFy1A_vbImUSw_Tx0u7_7jwxkDwlTt5WvGVsFFHsj9vgtNSnWHRzbGhbOSBocg0eWylgmYy3yZtdajRx6xQluRUewP_K66GsmA6xVmekUo0_ZzUPj61VQzTMR-knYE-pCd6V_qGS4qtUNeQ5nPLWT6hRPvnd3kK7CS22ijEErm3LaOY2DogGYIoBLvmdande226KW48hUgQPxsmOLoUl1tXMYsiRqHKAnWlzg4-e_BfRe3YsMUwlNPcqYf0hQ-mE-j4fVo79XJFFSWF8WxYKed-imDYeK9b6bQPP3ZPaqiMy7_d9Fxnb3i2Oo4XQPmrTpDkHbMovslBfBoJW4RSpXo3cn0QqcCDG2KfFS8HIYr68jXnyx7Ws3MeswdyEFSqx-XWmZa"
|
||||
},
|
||||
"Connection": {
|
||||
"ClientId": "53f4d5da-93a9-4584-82f9-b8fdf243b002",
|
||||
"ClientSecret": "blouh",
|
||||
"Authority": "localhost",
|
||||
"Audience": "localhost",
|
||||
"SiteAccessSheme": "http",
|
||||
"Port": 5000,
|
||||
"Scope": "profile"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue