Describe the bug
While working on my API, I added the @unique
directive to a field.
Then I ran prisma deploy
(note that adding or not @unique
would not resolve the bug).
And now, everytime I try to make a request to my own API (not prisma, my API that is using nexus
and nexus-prisma
), I get a 3105 error:
{
"data": {
"client": null
},
"errors": [
{
"message": "Your token is invalid. It might have expired or you might be using a token from a different project.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"client"
],
"code": 3015,
"requestId": "local:cjv88sj9q000c0792jxgwkq22"
}
]
}
But I've never implemented a jwt authentication method on my API, so it has to do with what prisma generated.
To Reproduce
Actually, I really don't know because I've never had this problem before and it has been weeks since I've run prisma deploy
.
I get back on it today and impossible to make it work.
I tried to upgrade prisma CLI, downgrade it, upgrade my node modules, downgrade them, upgrade prisma, downgrade it... :cry: still that same issue of authentication.
Expected behavior
Just to work as before: return the data from the database without an authentication token (which is neither the prisma service token, neither the prisma cluster token).
Versions (please complete the following information):
Postgres
1.31
& 1.32
prisma
CLI: prisma/1.32.2 node-v10.15-alpine
Ubuntu 18.04.2
"graphql": "^14.2.1",
"graphql-yoga": "^1.17.4",
"nexus": "^0.11.6",
"nexus-prisma": "^0.3.5",
"prisma-client-lib": "^1.31.1"
Additional context
I run both prisma and my API in docker containers.
Don't know if it can be related (don't guess so because it used to work as a charm before this bug).
I've noticed something (maybe not related), but I get different results whether I run prisma generate
or prisma deploy
.
With prisma deploy
:
generated/prisma-client/index.ts
// Code generated by Prisma ([email protected]). DO NOT EDIT.
With prisma generate
:
generated/prisma-client/index.ts
// Code generated by Prisma ([email protected]). DO NOT EDIT.
Obviously that's not the only diff between the two files, but if I paste it here, it would take hundreds of lines.
@nagman
Looks like you have set a secret property in your prisma.yml. Please pass that to prisma client as well so that I can authenticate with the API.
@pantharshit00
What do you mean by passing the secret to prisma client?
Doesn't prisma already handle this, according to https://www.prisma.io/docs/prisma-server/authentication-and-security-kke4/#prisma-services?
Also note that prisma generate automatically injects the secret into the generated Prisma client. So there's no need to generate a service token explicitly.
And did you mean "so that it can authenticate with the API"?
No, you will require pass the secret to the Prisma client, example: https://github.com/javascript-af/javascript-af/blob/9ab57f97da05d672f429919b35c3a163ca337b3e/packages/backend/src/apolloServer.ts#L8
Prisma.yml secret property just tells the Prisma server to protect that service with the given secret.
"It" is Prisma client
It's already done by the prisma generator.
Here's the end of generated/prisma-client/index.ts
:
export const Prisma = makePrismaClientClass<ClientConstructor<Prisma>>({
typeDefs,
models,
endpoint: `http://prisma:4466`,
secret: `${process.env["PRISMA_SECRET"]}`
});
export const prisma = new Prisma();
OMG! I solved it thanks to your pointing :smiley:
The fact was that PRISMA_SECRET
was not provided as an environment variable to my API in docker-compose.yml
.
I added it:
version: '3.4'
services:
api:
environment:
- PRISMA_SECRET=${PRISMA_SECRET}
And it works :tada:
Having a similar issue; tried this solution and the many others on the Prisma forum and no luck.
I have my PRISMA_SECRET
configured in a .env
file. I can use my base Prisma endpoint/admin dashboard without a problem if I generate a token using prisma token
and add it to query headers.
The problem arises when I try to query from an API generated by nexus. Like @nagman, my secret token is present in generated/prisma-client/index.ts
, but when I add this token as generated from the CLI to my API, I get the Your token is invalid.
error.
I've tried everything from resetting cache, to changing databases, to adding/removing management and secret keys, to changing ports, to generating my own secret token
using JWT, to trying ApolloServer instead of GraphQLServer from graphql-yoga
; the list goes on and on.
To make matters even worse, I get the same Your token is invalid.
even when I don't have any secret set at all.
Really looking for any possible help I can get; I've already spent a good 6 hours trying to fix this issue.
To make matters even worse, I get the same Your token is invalid. even when I don't have any secret set at all.
That's very odd, I've never had this issue without the secret keys. Would you be able to reproduce that bug from scratch?
Do your generated/prisma-client/index.ts
look like this?
export const Prisma = makePrismaClientClass<ClientConstructor<Prisma>>({
typeDefs,
models,
endpoint: `http://prisma:4466`,
secret: `${process.env["PRISMA_SECRET"]}`
});
export const prisma = new Prisma();
Yep, my generated Prisma constructor looks exactly like this, and I have a PRISMA_SECRET
set as an environment variable within the project.
I've been able to replicate this issue with the following procedure:
prisma init
> Create New Database
(PostgresQL
)> Prisma TypeScript Client
datamodel.prisma
.yarn add nexus graphql nexus-prisma prisma-client-lib graphql-yoga
yarn add typescript ts-node-dev --dev
prisma.yml
:hooks:
post-deploy:
- npx nexus-prisma-generate --client ./generated/prisma-client --output ./generated/nexus-prisma
tsconfig.json
.{
"compilerOptions": {
"sourceMap": true,
"outDir": "dist",
"strict": true,
"lib": ["esnext", "dom"]
}
}
npm init
in the project and add the "start script": "start": "ts-node-dev --no-notify --respawn --transpileOnly ./"
docker-compose up -d
.prisma deploy
.index.ts
.import { prisma } from './generated/prisma-client'
import datamodelInfo from './generated/nexus-prisma'
import * as path from 'path'
import { prismaObjectType, makePrismaSchema, } from 'nexus-prisma'
import { GraphQLServer } from 'graphql-yoga'
const Query = prismaObjectType({
name: 'Query',
definition(t) {
t.prismaFields(['*'])
}
})
const Mutation = prismaObjectType({
name: 'Mutation',
definition(t:any) {
t.prismaFields(['*'])
}
})
const schema = makePrismaSchema({
types: [ Query, Mutation ],
prisma: {
datamodelInfo,
client: prisma
},
outputs: {
schema: path.join(__dirname, './generated/schema.graphql'),
typegen: path.join(__dirname, './generated/nexus.ts'),
},
})
const server = new GraphQLServer({
schema,
context: (req) => ({
...req,
prisma
})
})
server.start(({ port }) => console.log(`Server is running on http://localhost:${port}`))
yarn start
.Authorization
. Now, I add a few custom resolvers into /src/
and import them into index.ts
as follows:...
import Mutations from './src'
...
const schema = makePrismaSchema({
types: [ Query, Mutation, ...Mutations ],
...
.env
file in the root of the project that looks as follows:...
PRISMA_SECRET=someprismasecret
...
secret: ${env:PRISMA_SECRET}
below datamodel
in prisma.yml
.PRISMA_SECRET: ${PRISMA_SECRET}
under services
>prisma
> environment
.prisma deploy
and generate a prisma token with prisma token
.yarn start
again.Authorization
HTTP header in the playground of the API server.{
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InNlcnZpY2UiOiJkZWZhdWx0QGRlZmF1bHQiLCJyb2xlcyI6WyJhZG1pbiJdfSwiaWF0IjoxNTU3NzQ4NDAzLCJleHAiOjE1NTgzNTMyMDN9.I8C7K_Q7EPtN6QnTH9yNyrA3oHqMXWjn9znqGKaIcxA"
}
Run any simple query
.
Finally,
{
"data": null,
"errors": [
{
"message": "Your token is invalid. It might have expired or you might be using a token from a different project.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"users"
],
"code": 3015,
"requestId": "local:cjvmbfyay00070878ixcq716i"
}
]
}
I see. But is your API running on your local host or in a docker container?
Because it's your API - on top of prisma - that needs to get the PRISMA_SECRET.
I explain myself:
Prisma runs in a docker container, and you provide it the PRISMA_SECRET env variable. That's perfect.
Like so, your prisma playground and prisma admin will be able to query the graphql API of prisma.
Now, you have your own API that provides a part of the prisma API (and some extra queries and mutations).
If you followed the prisma.io tutorial, you're running your API on your local host (in other words, you're not running it in docker or a virtual machine).
I did not follow the prisma.io tutorial as I didn't want to run my API on my local host.
Instead of this, I've created a docker-compose service for my API, so I ended up with something like this:
version: '3.4'
services:
api:
[...]
prisma:
[...]
db:
[...]
As my api service now runs in its own docker container, it needs to access to PRISMA_SECRET as well (or else it won't be able to decode the ${process.env["PRISMA_SECRET"]}
.
So if your api runs in docker, you must provide it the PRISMA_SECRET in the same way you did it for the prisma service.
But if you did not use docker for your api, you must export the PRISMA_SECRET in your terminal before executing your yarn start
command:
$ export PRISMA_SECRET="someprismasecret"
$ yarn start
Now, I'm not really an expert with .env files, and it seems like it should already work without needing to export the variables.
Maybe try to console.log(process.env)
in order to see if it the env variables get loaded.
Thanks for the explanation, the .env
variables are loaded just fine so that's not the issue. I understand the three layers I have for my Prisma server: database < graphql server < api layer, but I think your approach to dockerizing the api is a really good one.
Do you mind sharing the steps you took in doing so, so I could try that instead?
@anthonykrivonos
Your issue might be related to system time. Try syncing up your computer's time with an NTP.
Heads up for folks finding this from google:
GOOD:
import { config } from "dotenv";
config();
import { prisma } from "./generated/prisma-client";
BAD:
import { prisma } from "./generated/prisma-client";
import { config } from "dotenv";
config();
Prisma's generated client runs a constructor that grabs your env variables in the root scope, so when you import
, prisma will look at your env variables. And since you haven't loaded them in yet, prisma won't be able to generate a proper token for you.
export const Prisma = makePrismaClientClass<ClientConstructor<Prisma>>({
typeDefs,
models,
endpoint: `https://your-endpoint.com`,
secret: `${process.env["YOUR_SECRET"]}`
});
@Flaque that was it, thanks a million 馃憣
@Flaque Thank you!!!!!
Hey @Flaque !
Tried out https://github.com/prisma/prisma/issues/4492#issuecomment-495742958...
Didn't work for me. Same issue here.
I'm facing this issue right now, can't signup from playground!
Same Issue here as Omar
Same for me. No solutions seem to be working. Any fix?
Same issue here
Most helpful comment
Heads up for folks finding this from google:
You need to load your dotenv before importing prisma
GOOD:
BAD:
Why?
Prisma's generated client runs a constructor that grabs your env variables in the root scope, so when you
import
, prisma will look at your env variables. And since you haven't loaded them in yet, prisma won't be able to generate a proper token for you.