I have an entire API deployed and accessible with Swagger UI. It uses Basic Auth over HTTPS, and one can easily hit the Authorize button and enter credentials and things work great with the nice Try it out! feature.
However, I would like to make a public sandboxed version of the API with a shared username and password, that is always authenticated; that is, no one should ever have to bring up the authorization dialog to enter credentials.
I tried to enter an authorization based on the answer from another Stack Overflow question by putting the following code inside a script element on the HTML page:
window.swaggerUi.load();
swaggerUi.api.clientAuthorizations.add("key",
new SwaggerClient.ApiKeyAuthorization(
"Authorization", "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", "header"));
However, when I hit the Try it out! button the authorization is not used.
What would be the proper way to go about globally setting the auth header on all endpoints, so that no user has to enter the credentials manually?
(I know that might sound like a weird question, but like I mention, it is a public username/password.)
If you use Swagger UI v.3.13.0 or later, you can use the following methods to authorize the endpoints automatically:
preauthorizeBasic – for Basic auth
preauthorizeApiKey – for API keys and OpenAPI 3.x Bearer auth
To use these methods, the corresponding security schemes must be defined in your API definition. For example:
openapi: 3.0.0
...
components:
securitySchemes:
basicAuth:
type: http
scheme: basic
api_key:
type: apiKey
in: header
name: X-Api-Key
bearerAuth:
type: http
scheme: bearer
security:
- basicAuth: []
- api_key: []
- bearerAuth: []
Call preauthorizeNNN from the onComplete handler, like so:
// index.html
const ui = SwaggerUIBundle({
url: "https://my.api.com/swagger.yaml",
...
onComplete: function() {
// Default basic auth
ui.preauthorizeBasic("basicAuth", "username", "password");
// Default API key
ui.preauthorizeApiKey("api_key", "abcde12345");
// Default Bearer token
ui.preauthorizeApiKey("bearerAuth", "your_bearer_token");
}
})
In this example, "basicAuth", "api_key", and "bearerAuth" are the keys name of the security schemes as specified in the API definition.
I found a solution, using PasswordAuthorization instead of ApiKeyAuthorization.
The correct thing to do is to add the following line into the onComplete handler:
swaggerUi.api.clientAuthorizations.add("basicAuth",
new SwaggerClient.PasswordAuthorization(
"8939927d-4b8a-4a69-81e4-8290a83fd2e7",
"fbb7a689-2bb7-4f26-8697-d15c27ec9d86"));
swaggerUi is passed to the callback so this is the value to use. Also, make sure the name of your auth object matches the name in the YAML file.
Related
I know firebase sdk have a built in function to verified recaptcha response before doing sign-in with phone number but,
it is possible using manual captcha verifier API return response from https://www.google.com/recaptcha/api/siteverify as 2nd parameter in firebase.auth().signInWithPhoneNumber(phone, apiResponse) ?
I have different case to do it manually.
Thanks
With Recaptcha, you can introduce your own authorization method by using a decodable JWT as a second input. this will require a source of validation to generate the correct token
const captchaVerifier = {
type: 'recaptcha',
verify: () => Promise.resolve(token)
};
Source: https://pastebin.com/kaCarKC5
You could also make your own ReCaptcha that triggers the invisible ReCaptcha or simply use invisible ReCaptcha and implement your own later on per your app's design.
Reference: Invisible ReCaptcha
I am trying to authenticate an app with Azure AD. It's all good in localhost, it redirects to Azure AD where I enter details to authenticate, and it sends back the token that allows to view the resource.
Everything managed behind the scenes with the Microsoft.AspNetCore.Authentication.AzureAD.UI 3.1.10 in an aspnetcore 3.1 application.
My app runs on http://localhost:5000 and I can configure the redirectUri/replyUri at Azure AD for that application to support this url. All good.
The problem is in a different environment when my app runs in a service fabric cluster.
I can see the problem
AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application
When I inspect the url I can see that the redirect_uri has some url like this http://12.12.12.12/signin-oidc
The problem is double here. First of all I don't know which IP the cluster is gonna assign. Second, it is http, not https, and that's not supported by Azure AD.
Luckily my app has an external Url with a reverse proxy I can use to access. Something like https://myservicefabriccluster.com/MyApp
That Url I could configure as my redirect_uri in both my application and Azure AD, but I don't know how to do so.
My code has something like this:
services
.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
where I bind my settings.
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "76245c66-354e-4a94-b34d-...",
"TenantId": "59c56bd4-ce18-466a-b515-..."
},
I can see the AzureADOptions supports some other parameters such as Domain (not needed) or CallbackPath (which by default is ok being /signin-oidc) but there is nothing similar to ReplyUrl or RedirectUri where I can specify an absolute URL as the callback.
I have found a few similar issues without an answer. Others suggest some kind of tricks like a middleware that rewrites that parameter just before redirecting to Azure AD.
Certainly there must be an easier way to deal with this problem that I expect is not so strange. Any help please?
The solution to overwrite redirect_uri parameter with a custom value is to use the Events available in OpenIdConnect library. This library should be available as it's a dependency for Microsoft.AspNetCore.Authentication.AzureAD.UI, so this is my solution that, in addition to the standard properties for AzureADOptions it adds a flag to determine whether the redirect uri must be overwritten and a value to do so. I hope it's self explanatory
services
.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => configuration.Bind("AzureAd", options));
var isCustomRedirectUriRequired = configuration.GetValue<bool>("AzureAd:IsCustomRedirectUriRequired");
if (isCustomRedirectUriRequired)
{
services
.Configure<OpenIdConnectOptions>(
AzureADDefaults.OpenIdScheme,
options =>
{
options.Events =
new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = async ctx =>
{
ctx.ProtocolMessage.RedirectUri =
configuration.GetValue<string>("AzureAd:CustomRedirectUri");
await Task.Yield();
}
};
});
}
services
.AddAuthorization(
options =>
{
options.AddPolicy(
PolicyConstants.DashboardPolicy,
builder =>
{
builder
.AddAuthenticationSchemes(AzureADDefaults.AuthenticationScheme)
.RequireAuthenticatedUser();
});
});
And the appsettings.json would have something like this:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "76245c66-354e-4a94-b34d-...",
"TenantId": "59c56bd4-ce18-466a-b515-..."
"IsCustomRedirectUriRequired": true,
"CustomRedirectUri": "https://platform-cluster-development01.cubictelecom.com:19008/Scheduler/WebApi/signin-oidc"
},
Notice the IsCustomRedirectUriRequired and CustomRedirectUri are my custom properties that I read explicitly in order to overwrite (or not) the redirect uri query parameter when being redirected to the identity provider (i.e: Azure AD)
Looking at this, you should be configuring the public URL as the redirect URI, which is a value such as this:
https://myservicefabriccluster.com/MyApp
It looks like that the above library does not easily support this, and forces the redirect URI to be based on the HTTP listening URL of the code. As part of resolving this it is worth considering how you are writing your code:
This line of code indicates that your app is limited to only ever working with Azure AD:
- services.AddAzureAD
This line of code would ensure that your code works with both AzureAD and any other Authorization Server that meets the Open Id Connect standard:
- services.AddOpenIdConnect
The latter option also has an Events class with a commonly used OnRedirectToIdentityProvider operation that you can use to override the CallbackPath and provide a full RedirectUri.
Azure AD endpoints are standards based so you do not strictly have to use AzureAD specific libraries. Out of interest, I have a Single Page App Azure code sample that uses a neutral library like this, so I know this technique works.
I am trying to use the NelmioApiDocBundle for a Symfony 3.4 projects API documentation, while also trying to wrap my head around OAuth 2 authorization for the project API access to begin with.
So far I've followed this tutorial on how to get FOSOAuthServerBundle working. So far I can
1.) create a client using the command line command:
php bin/console fos:oauth-server:create-client --redirect-uri="___" --grant-type="authorization_code" --grant-type="password" --grant-type="refresh_token" --grant-type="token" --grant-type="client_credentials"
2.) I can also get an access token manually by visiting this url on my server
http://127.0.0.1:8000/oauth/v2/token?client_id=______&client_secret=________&grant_type=client_credentials
3.) I can use the token to access areas of my Symfony project requiring OAuth Access by including the token in a GET parameter
However, in the NelmioApiDocBundle Authorizations I cannot get this to work to completion. Here is a screenshot:
If enter my client_id and secret key it takes me to the Login Page, as expected. I can enter my login information and in takes me to the Approve or Deny Page, as expected. At this point if I click either Approve or Deny it tries to use a "redirect_uri" of http://localhost:3200/oauth2-redirect.html. No matter what I do I cannot change the redirect URI.
How to I get the a proper redirect URI?
Ok, this was actually easily fixed. You need to add a single line:
oauth2RedirectUrl: 'URLhere',
to the file init-swagger-ui.js which is located (Symfony 3.4) in web/bundles/nelmioapidoc/
The final file ended up looking like this:
window.onload = () => {
const data = JSON.parse(document.getElementById('swagger-data').innerText);
const ui = SwaggerUIBundle({
oauth2RedirectUrl: 'URLhere',
spec: data.spec,
dom_id: '#swagger-ui',
validatorUrl: null,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: 'StandaloneLayout'
});
window.ui = ui;
};
Also you likely are going to want to download the file oauth2-redirect.html from the Swagger project to include for the actual redirect.
I'm using the froatsnook:shopify atmosphere package to create an embedded public app on Shopify. I currently have a couple issues:
1) Getting the access token from the "code" query parameter after a user authenticates. As it mentions in the docs here, I'm supposed to use authenticator.getPermanentAccessToken(code) but what I don't understand is how to get call authenticator if the "code" parameter appears on the callback route (at that point, the authenticator I instantiated on the client pre-auth route is out of scope).
2) The "oAuth" function callback is never called for some reason, even when assigning it to Shopify.onAuth on the server.
3) The difference between post_auth_uri and redirect_uri ?
// I call this during 'onBeforeAction' for iron-router
function beforeAuth (query) {
// is this necessary..?
console.assert(Meteor.isClient);
// get shop name like 'myshop' from 'myshop.shopify.com';
const shop = query.shop.substring(0, query.shop.indexOf('.'));
// use api_key stored in settings
var api_key = Meteor.settings.public.shopify.api_key;
// Prepare to authenticate
var authenticator = new Shopify.PublicAppOAuthAuthenticator({
shop: shop,
api_key: api_key,
keyset: 'default',
embedded_app_sdk: true,
redirect_uri: 'https://45a04f23.ngrok.com/testContent',
//post_auth_uri: ???
// This is doesn't seem to be getting
// called after clicking through the OAuth dialog
onAuth: function(access_token) {
ShopifyCredentials.insert({
shop: shop,
api_key: api_key,
access_token: access_token
});
}
});
// Should i use something different with iron-router?
location.href = authenticator.auth_uri;
// how do i get code in this scope???
// authenticator.getPermanentAccessToken(code);
}
There are a few issues with the way you are trying to set up the authenticator, although it's not really your fault because the way Scenario 3 works in the docs is not an 'out of the box' solution and requires a bunch of custom code, including your own handler (I can provide a gist if you REALLY want to build your own handler, but I suggest using the new server-side onAuth callback instead)
1. Specifying a redirect_uri overrides the package's default redirect_uri handler which is Meteor.absoluteUrl("/__shopify-auth").
So instead, completely remove redirect_uri and put your testContent url in post_auth_uri instead.
2. ShopifyCredentials does not exist in this package. If you want to use it that way, make sure you actually have defined a collection called 'ShopifyCredentials' and insert the record from the server, not the client. Note that you will still need to add a keyset on the server for the API methods to work. If you are using user accounts and would like to permanently store credentials, I suggest saving the credentials to the database and adding the keyset via a server-side onAuth callback.
3. authenticator.getPermanentAccessToken(code) isn't useful unless you are using your own handler. Instead, you can just get access_token from the onAuth callback.
Also keep in mind that if you ever need to reauthenticate from inside the embedded app, you need to use window.top.location.href to break out of the iframe.
If you want a complete, working boilerplate example with user accounts see my gist here:
Authentication with Accounts and Persistent Keysets
If you aren't using accounts, you can use this gist instead, but please note that you really need to come up with some way to check that the current client has permission to request the keyset for a given shop before going to production:
Authentication with Persistent Keysets
I am using meteor to create a webpage with a dropdown list of Google Groups to select from and once selected, the Google contacts will be displayed.
I am using HTTP.call POST to Google's API and testing with the accessToken from mongoDB but when I use that token after some time it expires. I looked into implementing an authentication flow but it is getting very complicated since there is no sample code on Google for meteor. I am new to nodeJS, Javascript and Meteor. Am I going about this the wrong way? How would I implement this in meteor?
https://developers.google.com/accounts/docs/OAuth2?csw=1#expiration
To deal with the expiration of the accessToken, you will need to obtain the refreshToken from Google. With this refreshToken, you can obtain a new accessToken whenever necessary via a simple HTTP POST to Google's API. Here is the relevant documentation from Google. To obtain the refreshToken, you will need to request for offline access and may also need to force the approval prompt, as detailed in this SO post.
forceApprovalPrompt: {google: true},
requestOfflineToken: {google: true},
I recommend achieving all of the above using Meteor's HTTP package. All the tools are there. You've probably already figured it out:
var result = HTTP.post(
"https://www.googleapis.com/oauth2/v3/token",
{
params: {
'client_id': config.clientId,
'client_secret': config.secret,
'refresh_token': user.services.google.refreshToken,
'grant_type': 'refresh_token'
}
});
//Do some error checking here
var newAccessToken = result.data.access_token;
refresh_token - The refresh token returned from the authorization
code exchange.
client_id - The client ID obtained from the
Developers Console.
client_secret - The client secret obtained from
the Developers Console.
grant_type - As defined in the OAuth 2.0
specification, this field must contain a value of refresh_token.
result.data will be a JSON object with the following
{
"access_token":"1/fFBGRNJru1FQd44AzqT3Zg",
"expires_in":3920,
"token_type":"Bearer",
}
Have a look at this package its a little wrapper that does auto refresh for you:
here
I actually ended up building my own auth flow for with oauth handler because i needed to move away from a tokens linked to user profiles.