I'm trying to use Appwrite's Storage to store images and display them in my app, however when I use the getFileView, getFileDownload or getFilePreview methods the client throws a ERR_BLOCKED_BY_ORB.
I can access the file as an admin here: https://fra.cloud.appwrite.io/v1/storage/buckets/69b2d73500215daa4d65/files/69b2e559002dfb8caa8b/view?project=skincare-buddy&mode=admin
But if I remove the mode=admin it doesn't work. How do I make files publicly accessible? Or at least accessible to the logged-in user?
I'm using Next.js, so the session is stored as a cookie and then populated back into the Appwrite client with client.setSession() so I'm not sure if that migh tbe related.
I've been sort of able to solve it by giving the file the Permission.read(Role.any()) but that's not really ideal and it would be better if there's a way to manually pass the session to the URL.
You need to generate a Token for that file and then generate a link for that file with that token if you want to share that file with others. Tokens have life-time property which you can utilise.
Refer to this
I get that, however the thing is I'd like the user who creates the file to have access to it only, really, but because I'm using client.setSession it looks like the file API basically considers the request unauthorized. Is there no way to pass the session to the API via query params?
Do you have row level permissions on ?
And Tokens seem to only be available from node-appwrite so I can only generate those on the server, which I just did as a workaround. I have a Next.js API route that redirects to Appwrite's file URL after generating a token if none exist. But that seems extremely hacky.
Yep. The user has read access, as I mentioned that works fine. The issue is more so that the view URL is useless because the user isn't authorized via cookies.
Or at least not an Appwrite cookie lol.
So the user who uploads let's say a picture is not able to see the picture if he tries to open it by clicking the link generated via the FileView or something property?
Yes because when the user logs in I run createSession on the server, store it in a cookie on my site, then populate the client with the session using setSession. So Appwrite doesn't really "know" the user when a direct request is made to the API without headers which is what happens when I try to load images.
The user can read/update the file just fine, not view it because of the auth.
That should not happen even if it's client sided
Appwrite has no way of knowing the user. How could it if I am logging them in server-side?
Oh yeah
My bad
That did happen to me when I was building a g-drive clone I was not able to view the file unless I viewed it in admin mode or downloaded it just to see it
The only solution was the token
I had a similar problem. There’s also an issue on GitHub repo. Take a look at my comment here https://github.com/appwrite/appwrite/issues/11335#issuecomment-3924064947
I had to use appwrite client.call() method to get it to work. Hacky but it works
I might have explained my issue poorly, I think it's different to yours <@243124669685694474> because you said your error is a 404 for the bucket, and that you have permissions for the role "any" with full CRUD enabled, and no File Security. In my case I only have create enabled for users, and File Security so when a file is created I do this:
const fileUpload = await storage.createFile({
bucketId,
fileId: ID.unique(),
file: image,
permissions: [
Permission.read(Role.user(user.$id)),
Permission.update(Role.user(user.$id)),
Permission.delete(Role.user(user.$id)),
],
});```
But my user logs into my app server-side and I store the session in my own cookie, not Appwrite's:
```ts
export async function signInWithEmail(formData: FormData) {
const email = formData.get("email")! as string;
const password = formData.get("password")! as string;
const { account } = await createAdminClient();
const session = await account.createEmailPasswordSession({
email,
password,
});
(await cookies()).set(APPWRITE_SESSION_KEY, session.secret, {
path: "/",
httpOnly: true,
sameSite: "lax",
secure: process.env.NODE_ENV === "production",
});
redirect("/dashboard");
}```
Which means that there aren't any Appwrite cookies for the user to be authenticated when I pass an image URL to the `<img>` tag.
Hence why I had to create this trick-route that generates a File Token on-the-fly:
export async function GET(
_: NextRequest,
ctx: RouteContext<"/api/files/[id]">,
) {
const { id } = await ctx.params;
const { storage } = await createSessionClient();
const file = await storage.getFile({
bucketId,
fileId: id,
});
const { tokens } = await createAdminClient();
let token: string | undefined;
const { tokens: tokensList } = await tokens.list({
bucketId: file.bucketId,
fileId: file.$id,
total: false,
});
if (tokensList.length > 0) {
token = tokensList[0].secret;
} else {
token = await tokens
.createFileToken({
bucketId: file.bucketId,
fileId: file.$id,
})
.then((tok) => tok.secret);
}
const { storage: storageClient } = createClient();
return NextResponse.redirect(
storageClient.getFileView({
bucketId: file.bucketId,
fileId: file.$id,
token,
}),
);
}```
Appwrite should ideally have a way users can access files by appending ?session to the /view URL.
Okay I think I know what's going on. And I think that I had not quite identical, but similar issue.
export async function signInWithEmail(formData: FormData) {
const email = formData.get("email")! as string;
const password = formData.get("password")! as string;
const { account } = await createAdminClient();
const session = await account.createEmailPasswordSession({
email,
password,
});
// up to this point everything is quite right
// but there:
// you set the cookie that will never be sent to appwrite, because of how cookies work
// so the APPWRITE_SESSION_KEY will never be send anywhere
(await cookies()).set(APPWRITE_SESSION_KEY, session.secret, {
path: "/",
httpOnly: true,
sameSite: "lax",
secure: process.env.NODE_ENV === "production",
});
redirect("/dashboard");
}
what you can do is to call:
client.call()
with your url, and manually pass X-Fallback-Cookies header, or genereate JWT and pass X-Appwrite-JWT.
Recommended threads
- sh: vite: Permission denied
When installing the vue starter template as site and then adding DaisyUI, i get the error `sh: vite: Permission denied`. I also got this issue (with a fresh tem...
- Appwrite Auth & Function don't reveal cl...
When I execute a function or sign in with my Flutter app, Appwrite does not show my real IP: instead, it seems that Appwrite shows Fastly CDN IP address.
- All function deployments fail (node 18-2...
Error: bash: /usr/local/server/helpers/build-cache.sh: No such file or directory Sidecar error: Build archive was not created at /mnt/code/code.tar.gz Scope: ...