I have an asp.net core api project and I want to be able to authenticate via google inside swagger. This is how I add the authentication services:
builder.Services
.AddAuthentication()
.AddCookie()
.AddGoogle();
This is the options setup class for "AuthenticationOptions":
public sealed class AuthenticationOptionsSetup
: IConfigureOptions<AuthenticationOptions>
{
public void Configure(AuthenticationOptions options)
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
}
}
The options setup class for "GoogleOptions":
public sealed class GoogleOptionsSetup(IConfiguration configuration)
: IConfigureNamedOptions<GoogleOptions>
{
public void Configure(GoogleOptions options)
{
options.ClientId = configuration[GoogleOAuthSettings.ClientIdName]!;
options.ClientSecret = configuration[GoogleOAuthSettings.ClientSecretName]!;
options.SaveTokens = true;
}
public void Configure(string? name, GoogleOptions options) => Configure(options);
}
The configuration of my "SwaggerGenOptions":
options.AddSecurityDefinition(
SecurityDefinitionName,
new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new()
{
AuthorizationCode = new()
{
AuthorizationUrl = new(GoogleDefaults.AuthorizationEndpoint),
TokenUrl = new(GoogleDefaults.TokenEndpoint),
Scopes = GoogleOAuthSettings.Scopes
}
}
});
options.AddSecurityRequirement(new()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = SecurityDefinitionName
}
},
new List<string>()
}
});
options.OperationFilter<AuthorizationOperationFilter>();
And the "AuthorizationOperationFilter" class:
public sealed class AuthorizationOperationFilter : IOperationFilter
{
private const string SecurityDefinitionName = "google_auth";
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" });
operation.Security = new List<OpenApiSecurityRequirement>
{
new()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = SecurityDefinitionName
}
},
new List<string>()
}
}
};
}
}
Also, this is my swagger UI options:
options.OAuthAppName(GoogleDefaults.DisplayName);
options.OAuthClientId(configuration[GoogleOAuthSettings.ClientIdName]!);
options.OAuthClientSecret(configuration[GoogleOAuthSettings.ClientSecretName]!);
options.OAuthScopes([.. GoogleOAuthSettings.Scopes.Keys]);
The problem is when I click the "Authorize" button in swagger page, I am redirected to google login page and after that, redirected back to my swagger page and everything seems to be working. Now, if I call a protected api via clicking the "Execute" button on swagger page, it returns "Undocumented, but if I enter the address of that api in my search bar and hit enter, The api is called properly and I am authorized. As shown in the capture, I am apparently authorized but it does not work. What am I missing ?
So, I finally learned what was wrong with my approach. First of all, Apparently, swagger extracts the access token by default, not the ID token which is a JWT and the one I need. Also, in my case which is a web application that will eventually have a front-end, fetching the ID token is the responsibility of front-end as there are available tools and libraries apparently provided by google to achieve this. So now, instead of worrying about google authentication, I added regular JWT authentication to my APIs and my login API that allows anonymous, simply receives a JWT ID token from query and uses it to issue it's own JWT.