403 Error when using generated Sas token to display blobs from Azure blob storage - next.js

I've been trying to display images from Azure blob storage on my web app for a while now.
My storage account SAS token is:
?sv=2021-06-08&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2022-12-09T08:03:09Z&st=2022-11-09T08:03:09Z&spr=https&sig=SIGNATURE_HERE
This SAS token includes all permissions and allows all resource types and services.
To generate a SAS token to view a blob, I go through the following steps:
1. Getting the blobService:
const blobService = new
BlobServiceClient(https://${storageAccountName}.blob.core.windows.net/?${storageAccountSasToken});
2. Creating a containerClient:
const containerClient = blobService.getContainerClient(containerName);
3. creating a sasOptions object:
const sasOptions = {containerName: containerName, blobName: blobName, startsOn: sasStartTime, expiresOn: sasExpiryTime, permissions: "racwdt" as unknown as BlobSASPermissions};
4. Generating SAS token with the parameters:
generateBlobSASQueryParameters(sasOptions, sharedKeyCredential).toString();
5. Sending the blobURL (with the SAS token attached) back to the user:
const blobURL = containerClient.getBlockBlobClient(blobName).url;
The problem is, when using the blobURL as src for my Image tag, I get a 403 (forbidden) error:
Server failed to authenticate the request. Make sure the value of
Authorization header is formed correctly including the signature.
the faulty blobURL in question:
https://mywebsite.blob.core.windows.net/container/profilePictures%2Fpicture.png?sv=2021-06-08&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2022-12-09T08:03:09Z&st=2022-11-09T08:03:09Z&spr=https&sig=CITlY0uPxBCGdBeMtIxxJafJM61HQlhooR5ZnDiPHuE%3D
The Error:
AuthenticationFailed
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:df81f724-f01e-000e-593e-f41f7f000000 Time:2022-11-09T13:24:08.3305270Z
Signature did not match. String to sign used was STORAGE_ACCOUNT_NAME racwdt bfqt sc 2022-11-09T12:31:47Z 2022-12-09T20:31:47Z https 2021-06-08
Additional information:
The sasToken env variable includes "?" at the start of the string
All containers are PRIVATE.
My storage account is only accessible through a specific virtual network
My website's domain is listed on "Allowed Origins" in CORS tab, as well as localhost:3000
Uploading to Blob storage works, So Its safe to assume that the problem is solely related to the generated SAS token
Any assistance would be gladly appreciated :)

I tried in my environment and got below results:
Code:
var storage = require("#azure/storage-blob")
const accountname ="storage13261";
const key = "< Account key >";
const cred = new storage.StorageSharedKeyCredential(accountname,key);
const blobServiceClient = new storage.BlobServiceClient(`https://${accountname}.blob.core.windows.net`,cred);
const containerName="test";
const client =blobServiceClient.getContainerClient(containerName)
const blobName="nature.png";
const blobClient = client.getBlobClient(blobName);
const blobSAS = storage.generateBlobSASQueryParameters({
containerName,
blobName,
permissions: storage.BlobSASPermissions.parse("racwdt"),
startsOn: new Date(),
expiresOn: new Date(new Date().valueOf() + 86400)
},
cred
).toString();
const sasUrl= blobClient.url+"?"+blobSAS;
console.log(sasUrl);
Console:
The problem is in your SAS token where storage service is uses racwdt but in you SAS has rwdlacupiytfx that may cause to display an image.
I checked the Url + SAS token in the browser it perfectly worked.
Reference:
Grant limited access to data with shared access signatures (SAS) - Azure Storage | Microsoft Learn
Updated:
You can get both SAS and SAS-URL manually with check the permission by refer the below image.

Related

Why I can not connect to Firebase?

I'm trying to connect my app to firebase but the only response I get is not the response json I need from firebase. I included my call to firebase below. Is the url not correct? The response I'm getting back is not the json object made with firebase that I created.
``
<script>
(async function call () {
console.log("hello")
const endpoint = url
console.log(endpoint)
async function initiation () {
const result = await fetch(endpoint, {mode: "no-cors"})
const data = await result
console.log(data)
}
initiation()
})()
</script>
``
is your database in us-central1?
according to documentation [1] "the form https://<"databaseName">.firebaseio.com (for us-central1 databases) or https://<"databaseName"><"region">.firebasedatabase.app (for databases in all other locations)."
If its in another region you should try with https://<"databaseName"><"region">.firebasedatabase.app
[1]https://firebase.google.com/docs/database/web/start#initialize_the_javascript_sdk
The structure within your code seems odd, if you are implementing the CDN you need to initiate your app with your project credentials, right now you are only accessing a real-time database as a public request and does not provide any additional validators as the database is most likely to have Security Rules enabled.
To request data from the endpoint, you need to also include a .json at the end of the URL https://[PROJECT_ID].firebaseio.com/users/jack/name.json
Source: https://firebase.google.com/docs/reference/rest/database#section-get

Google Storage - signed url Request had insufficient authentication scopes

I'm using the google cloud nodejs storage library to upload some images to cloud storage. This all works fine. I'm then trying to generate a signed URL immediately after uploading the file, using the same storage object that uploaded the file in the first place but I receive the following error:
Request had insufficient authentication scopes
I'm not sure why this would be happening if it's all linked to the same service account that uploaded in the first place. (For what it's worth it's a firebase app).
The code is below:
const Storage = require('#google-cloud/storage');
storage = new Storage();
storage.bucket(bucketName).upload(event.file.pathName, {
// Support for HTTP requests made with `Accept-Encoding: gzip`
gzip: true,
destination: gcsname,
metadata: {
// Enable long-lived HTTP caching headers
// Use only if the contents of the file will never change
// (If the contents will change, use cacheControl: 'no-cache')
cacheControl: 'public, max-age=31536000'
},
}).then(result => {
let url = `https://storage.googleapis.com/${bucketName}/${gcsname}`;
const options = {
action: 'read',
expires: Date.now() + 1000 * 60 * 60, // one hour
};
// Get a signed URL for the file
storage.bucket(bucketName).file(gcsname).getSignedUrl(options).then(result => {
console.log("generated signed url", result);
}).catch(err => {
console.log("err occurred", err)
})
})
The bucket itself isn't public and neither are the objects, but it's my understanding that I should still be able to generate a signed url. The app itself is running on GCP compute engine, hence not passing any options to the new Storage() - passing options in fact also makes the upload fail.
Can anyone advise on what I'm doing wrong?
With the limited amount of information I have, here's a few things that you could be missing based on the error you are receiving:
The Identity and Access Management (IAM) API must be enabled for the project
The Compute Engine service account needs the iam.serviceAccounts.signBlob permission, available to the "Service Account Token Creator" role.
Additionally, you can find more documentation regarding the topic here.
https://cloud.google.com/storage/docs/access-control/signed-urls
https://cloud.google.com/storage/docs/access-control/signing-urls-manually

How to get external login profile picture from Microsoft account in asp.net core

how can I get profile picture from Microsoft account using Microsoft.AspNetCore.Authentication.Facebook library? I tried using Claims, but they don't have profile picture value... I also tried looking in account's source control by checking image url, but I noticed that the url is made of some parameters that I can't get with claims, so I can't construct url like I can with facebook... Can someone can help me?
You can obtain the profile picture from Microsoft accounts by using Microsoft Graph:
https://developer.microsoft.com/en-us/graph/quick-start
Specific instructions on how to request the profile picture:
https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/profilephoto_get
If you follow the quick start (select asp.net, click "Get an app ID and secret" and download the sample code), it's easy to obtain the data like so:
GraphServiceClient graphClient = SDKHelper.GetAuthenticatedClient();
var photoStream = await graphService.GetCurrentUserPhotoStreamAsync(graphClient);
EDIT: Sorry, forgot the asp.net core part (it doesn't seem that Microsoft.Identity.Client is available for asp.net core).
In ExternalLoginCallback you can obtain the access token from the ExternalLoginInfo object returned by var info = await _signInManager.GetExternalLoginInfoAsync();
Remember to set SaveTokens to true when configuring authentication (otherwise the access token won't be available):
services.AddAuthentication()
.AddMicrosoftAccount(options =>
{
options.ClientId = Configuration["ExternalProviders:Microsoft:ClientId"];
options.ClientSecret = Configuration["ExternalProviders:Microsoft:ClientSecret"];
options.SaveTokens = true;
...
Then it's just a matter of making a http request - something like this:
var httpClient = new HttpClient();
httpClient.SetBearerToken(info.AuthenticationTokens.Where(t => t.Name.Equals("access_token")).First().Value);
var pictureResult = httpClient.GetAsync("https://graph.microsoft.com/v1.0/me/photo/$value").Result;

Get shorter file URL from Google Cloud Storage (with Firebase Cloud Functions)

I have the following Firebase Cloud Function to get the URL of the file stored in Google Cloud Storage.
const gcs = require('#google-cloud/storage')({keyFilename: 'service-account.json'});
exports.generateFileLink = functions.storage.object().onChange(event => {
const object = event.data;
const filePath = object.name;
const bucket = gcs.bucket(object.bucket);
const file = bucket.file(filePath);
const action = 'read';
const expires = '03-09-2491';
return file.getSignedUrl({action, expires}).then(signedUrls => {
console.log(signedUrls[0])
});
})
This returns the correct URL, but it is over 600 characters long. The URL for the same file as seen on the Firebase web console is less than 200 characters long. Is there any way I can retrieve the URL using firebase-admin or firebase-functions modules to get the shorter URL?
Short answer is that we're working on a firebase-admin Storage client, but it's still a little ways away. For now, signed URLs are the way to go if you need to create a download URL in a function.
Why do you need to generate signed URLs in the function vs using the download URLs provided by Firebase? Is it that you can't retrieve the URL via a client in the function and you need to move it somewhere else?

Where to find auth.token data, inside firebase objects

I am using signInWithCustomToken, after authentication I can not find where is stored my custom claims data which I have set in the server side(createCustomToken).
I can see them in firebase rules via auth.token, but how can I access them through firebase objects from within my javascript code.
The information in the token is not automatically available to your application code. But it is embedded in the token, so you can decode it yourself:
function parseJwt (token) {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace('-', '+').replace('_', '/');
return JSON.parse(window.atob(base64));
};
var user = firebase.auth().currentUser
user.getToken().then(data => {
console.log(parseJwt(data));
});
The function to parse the JWT comes from this question: How to decode jwt token in javascript
You'll note that it doesn't verify that the ID token is valid. That seems fine to me in client-side code, since the information will be used by the user themselves anyway. But if you do want to verify the token, you'll have to use a more involved method.

Resources