I recently restricted an api key to accept requests from specific websites, but I use the same api key from Firebase Cloud Functions for Places search.
What url do I add for the cloud functions request?
Url is built like this
const urlFindPlaceFromText = "https://maps.googleapis.com/maps/api/place/findplacefromtext";
const fields = "formatted_address,name,geometry,icon,rating,price_level,place_id";
const location = "point:$latitude, $longitude";
const url = `${urlFindPlaceFromText}/json?input=${searchString}&inputtype=textquery&language=en&fields=${fields}&locationbias=${location}&key=${apiKey}`;
const placesRequest = await axios.get(url)
Response:
data: {
> candidates: [],
> error_message: 'API keys with referer restrictions cannot be used with this API.',
> status: 'REQUEST_DENIED'
> }
The error you are seeing looks like you are making the API call server side. Because you have placed a referrer restriction on your API key, it will be limited to executing on the browser with the web service APIs.
As mentioned in the comments above,you may create a separate key to use server-side. You can change your restriction from a browser restriction to a server restriction by using IP addresses to restrict access, instead of browser referrers.
Check this APIs FAQ on switching key type to a server restricted key
Also check these similar example for more information:
Key restrictions by IP address not working
How to get IP address from client
Cloud function secure HTTPS endpoint with API key
API keys referrer restrictions cannot be used with this API
error
Related
I have a service account credentials json file with client_email and private_key.
Is it then possible to programmatically retrieve from serviceaccount credentials which api's are enabled? I don't mean a solution like go to console.cloud.google.com but from within nodejs. Thanks!
You will need to know the Project ID as well. The answer from #wardenunleashed is for API Gateway. That does not cover which Google APIs are enabled.
APIs are enabled per project, so you must specify the project to query.
A service account JSON key file contains the Project ID for the project that owns the service account.
The private_key_id is also important. That ID is used to lookup the public key for validating private key signatures.
Google has an API Gateway Client Library for NodeJS with the desired capability
const projectId = 'my-project';
const {ApiGatewayServiceClient} = require('#google-cloud/api-gateway');
const client = new ApiGatewayServiceClient();
async function listApis() {
const [apis] = await client.listApis({
parent: `projects/${projectId}/locations/global`,
});
for (const api of apis) {
console.info(`name: ${api.name}`);
}
}
listApis();
I've never configured a CDN before and I'm looking for guidance for how to approach the configuration for my scenario.
For context, I'm currently using Azure Verizon Premium CDN and an Azure App service (.Net Core). My authentication platform is Azure Active Directory.
I have a static web app that has lots of static content (hundreds of files). Users hit the website at (www.mysite.azurewebsites.net/index.html). Index.html then fetches large amounts of static content (various, images, video, metadata). Initially, the requirement was to just serve the content publicly but now I have requirements around restricting access to some the content based on whether or not a user has a certain role & the user hits a certain path. I also need to be able to keep some content public and highly available to end users.
Before authorization requirements came in, I was able to successfully set up a CDN endpoint (www.mysite-cdn.azureedge.net) and point it to my app service no problem! I can hit the site and see the site content from the cdn endpoint without auth no issue.
Problems came when I added authentication to my site my CDN is redirected during the authentication flow back to the origin endpoint. The origin authentication middleware (Nuget: Microsoft.Identity.Web) automatically assembles the callback uri for AAD as "www.mysite.azurewebsites.net/signin-oidc". So the present flow for a user hitting the CDN endpoint returns them to an error page on the app service endpoint. Although if they manually redirect to "www.mysite.azurewebsites.net" they are logged in, I don't want to redirect the user back to origin, I want to keep them on www.mysite-cdn.azurewebsites.net.
Essentially, I want to be able to enable these flows:
Public End User -> CDN Endpoint + Public path -> (CDN request origin and caches) -> End user sees site at CDN endpoint
Internal End User -> CDN Endpoint + Private path -> (CDN request origin and has access) -> User is permitted into site at CDN endpoint
Internal End User -> CDN Endpoint + Private path -> (CDN request origin and DOESN’T have access) -> User is redirected to public CDN endpoint (or unauthorized page)
This is the auth check for each static file in OnPrepareResponse for static file options. This checks authentication before requesting a static asset in this folder on the server. This works fine without the CDN. It should be noted that I also do role checks and this has been simplified for the sake of the example as it repos with Authentication.
OnPrepareResponse = staticContext =>
{
// require authentication
if (authenticate &&
!staticContext.Context.User.Identity.IsAuthenticated)
{
// Redirect back to index sign in page all unauthorized requests
staticContext.Context.Response.Redirect(unauthenticatedRedirectPath);
}
},
I did find this stack overflow which seemed similar to my problem however I am using a different NuGet package (Microsoft.Identity.Web). I implemented a check to redirect however that did not seem to work and cause an infinite loop when trying to login.
Action<MicrosoftIdentityOptions> _configureMsOptions = (options) =>
{
options.Instance = Configuration["AzureAd:Instance"];
options.Domain = Configuration["AzureAd:Domain"];
options.ClientId = Configuration["AzureAd:ClientId"];
options.TenantId = Configuration["AzureAd:TenantId"];
options.CallbackPath = Configuration["AzureAd:CallbackPath"];
options.Events.OnRedirectToIdentityProvider = async (context) =>
{
// This check doesn’t work because the request host always is mysite.azurewebsites.net in this context
// if (context.Request.Host.Value.Contains("mysite-cdn"))
// {
context.ProtocolMessage.RedirectUri = "https://" + "mysite-cdn-dev.azureedge.net/" + Configuration["AzureAd:CallbackPath"];
//}
};
};
I've started looking into Azure Front door, as that seems to be more applicable to my use case but haven't set it up. It provides some level of caching/POP as well as security. It looks like it's also possible to use with Azure AD with some web server tweaking. It would be good to know from others if Azure Front Door sounds like a more sensible CDN solution approach vs Azure CDN.
I've also looked into Azure CDN Token authentication- but that seems to be something that also requires me to stamp each request with an Auth token. It changes my architecture such that I can no longer just 'point' my cdn at the web app and instead my app would give the browser a token so it could securely request each asset.
All that said, I'm looking for guidance on how best to configure an application using a CDN while also using authentication. Thanks!
I write a signup webpage with nodejs, and in this webpage, I use ajax to call the function signup like this
$.ajax({
method: "POST",
url: "/signup",
data: { tel: tel, password: password}
})
And in app.js, the signup function like this
.post('/signup', async (ctx) => {
//do something
})
And now everyone can call the signup function with the url http://domain/signup without visiting the signup webpage, I think it's a mistake, I only want the local program can call this function, how can I fix this?
Typically it's either API Keys for doling out general access, or IP-based restrictions at either the application or network level.
API Keys are a token that identifies and authenticates an endpoint. You can also use it to track usage and/or ban abuse. For example, see Google Maps' documentation about using their API. Then all API calls have that key:
https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap
This allows the server to parse the key, check against it's key database or whatever, and allow access. You'll need to use HTTPS for this if it's over any public network.
IP or other network restrictions are easier to setup and best when you have a 1:1 relationship with your API. That is, your application alone accesses this API, and you control all the servers, etc.
In an in Azure Functions with HTTP trigger, where in the HttpRequestMessage instance are the credentials (username and password) in a basic HTTP Authentication scheme?
I was able to find a username:password string encoded in base64 in:
request.Headers.Authorization.Parameter
Where request is an instance of HttpRequestMessage
Basic is not an option, nor is any other commonplace auth scheme available right now, unfortunately. Other than Anonymous, HTTP Functions auth is based on keys generated and stored in Azure. Three types of keys are currently available:
Admin - requires a "host" key (host keys are shared by all functions)
System - requires the special "master" host key
Functions - requires a key defined for the individual function
Keys are documented here and can be managed from the "Manage" button when you expand a given Function in the portal.
Microsoft is working on adding a new token-based User auth type based on tokens instead of keys. You can read about it in the following github issue:
https://github.com/Azure/azure-functions-host/issues/33
I have an on-premise ASP.NET Web API that's querying on-premise data. The plan is for the client web application to call an Azure Function which will deal with authentication (Azure AD B2C) and validating the request before actually forwarding the request to the on-premise API itself (over a VPN).
The API is generating Hypermedia links that point to the API itself. This works nicely when querying the API directly as each of the links helps in the discovery of the application.
This API is currently in use locally within the organisation, but we now need to expose it so it can be consumed over the web. We don't want to expose the API directly, we'd rather route it through a Function App that can authenticate, validate and perform any other logic we may need.
The question I have is, how would you translate these URLs to an endpoint in the Azure Function? i.e., I would really like the consuming web application to be able to use these Hypermedia links directly, and have the Azure Function route them to the correct API endpoint.
In an ideal world, we'd have the links exposed on the client, which would map to the resource. As the API isn't exposed, how do we route it via the Function App?
It sounds like what you want is for Azure Functions to operate as a reverse proxy.
One trick to achieve this is to have one HttpTrigger that catches all traffic that hits your function application. You can do this by setting the properties route: "{*uri}" and methods: ["get", "post", "put", "patch", "delete"] in the function.json. You can add additional HTTP methods to the methods list as necessary. These should catch all requests in the form "https://{app-name}.azurefunctions.net/api/*".
The code below is a rough outline of how you could achieve the redirect from your function app to the unexposed API. In it's current representation, the relative URI path after /api/ will be redirected to your unexposed api with the exact same body request.
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
//Validation logic here
string actualUrl = "{hosturl}/";
string proxyUrl = "https://{app-name}.azurewebsites.net/api/";
req.RequestUri = new Uri(req.RequestUri.ToString().Replace(proxyUrl, actualUrl));
req.Headers.Host = req.RequestUri.Host;
using(var client = new HttpClient())
{
return await client.SendAsync(req);
}
}
You can now generate all of your Hypermedia links pointing to your function hostname, and they will be properly redirected.
NOTE: If you expect many instances of the function to spin up (i.e. a high concurrent usage of your function), then it is possible that you will run into SocketException errors as documented here.