Comments (12)
Any update on this? @lvauvillier I also wasn't able to get your workaround to work. I get the following error (looks like @Maetes got the same one):
Interface 'NexusContext' cannot simultaneously extend types 'Context' and 'Context'.
Named property ''token'' of types 'Context' and 'Context' are not identical.
from nexus-plugin-jwt-auth.
Thanks for bringing this up! I had a conversation with the creator of https://github.com/lvauvillier/nexus-plugin-shield and the way we discussed handling this is by having a token interface that at least contains some common JWT object properties.
export interface Token {
sub?: string
iss?: string
aud?: string
exp?: number
iat?: number
name?: string
admin?: boolean
}
from nexus-plugin-jwt-auth.
Interesting thought too about passing an optional parameter to the plugin. Possible can be done by leveraging generics? Looking into it 😄
from nexus-plugin-jwt-auth.
I like the idea of the generic a lot. At the very least, when I go into the source of the plugin (runtime.js ~ line 30) and change the type string to my desired version:
token: '{ userId: number, username: string}'
The type safety works as I would expect. I think generics would be nicer than that but its definitely an option
from nexus-plugin-jwt-auth.
@kylejreed I was able to look into this a bit more this morning and this is what I've come up with:
function genSignature<T extends object>(object: T) {
const keys = Object.keys(object)
const values = keys.map(key => { return object[key]})
let properties: String[] = []
for (let index = 0; index < keys.length; index++) {
const key = keys[index]
const value = values[index]
if (typeof value == 'object') {
properties.push(' ' + key + ': ' + genSignature(value) + ' | undefined | null')
} else {
properties.push(' ' + key + ': ' + typeof value + ' | undefined | null')
}
}
return '{' + properties + ' }'
}
Usage of this function would look like:
interface Token {
sub?: string
iss?: string
aud?: string
exp?: number
iat?: number
name?: string
admin?: boolean
}
let token: Token = {
sub: '123',
iss: '14r',
aud: 'wow',
exp: 0,
iat: 1,
name: 'Test',
admin: false
}
// standard
console.log(genSignature(token))
// returns '{ sub: string | undefined | null, iss: string | undefined | null, aud: string | undefined | null, exp: number | undefined | null, iat: number | undefined | null, name: string | undefined | null, admin: boolean | undefined | null }
interface User {
name?: string
id?: number
token?: Token
}
const user: User = {
name: 'Cameron',
id: 12,
token
}
// recursive
console.log(genSignature(user))
// returns '{ name: string | undefined | null, id: number | undefined | null, token: { sub: string | undefined | null, iss: string | undefined | null, aud: string | undefined | null, exp: number | undefined | null, iat: number | undefined | null, name: string | undefined | null, admin: boolean | undefined | null } | undefined | null }'
This function can take an object and generate it's signature. This signature can then be passed into the (runtime.js ~ line 30)
typegen.
Here are the drawbacks I'd like to fix:
- The function currently takes an instance of an
interface
rather than the type itself. Ideally I could just pass theinterface
directly. I was having a hard time coming across any documentation on how this might be possible. - The function has no way of determining whether or not a property can be
optional
, therefore I append the types ofnull
andundefined
to every value. Ideally the function could check whether of not the property is optional and then and only then apply thenull | undefined
to the type.
Thoughts? I'm relatively new to Typescript and would love to hear any advice on how this can be improved.
from nexus-plugin-jwt-auth.
Hi @Camji55,
Take a look how nexus generates context types from addToContext
user function calls.
They walk through sources files and use the ts compiler to retrieve types and signatures:
https://github.com/graphql-nexus/nexus/blob/master/src/lib/add-to-context-extractor/extractor.ts#L24
This is an example to how nexus properly generates types if the token extraction is done manually and pass through an addToContext
call:
// app.ts
import { extractToken } from "./helpers/token"
schema.addToContext((req) => {
return {
token: extractToken(req)
};
});
// helpers/token.ts
export interface Token {
sub?: string;
iss?: string;
aud?: string;
exp?: number;
iat?: number;
name?: string;
admin?: boolean;
}
export function extractToken(req: any) {
const Authorization = req.get("Authorization");
if (Authorization) {
const token = Authorization.replace("Bearer ", "");
return verify(token, process.env.TOKEN_SECRET || "") as Token;
}
}
In the nexus extractor, the ts compiler extract the signature of my extractToken
function and generates types properly
// content of generated typegen-nexus-context/index.d.ts
import app from 'nexus'
// Imports for types referenced by context types.
import { Token } from '/path_to_my_project/src/helpers/token'
// Tap into Nexus' global context interface. Make all local context interfaces merge into it.
declare global {
export interface NexusContext extends Context {}
}
// The context types extracted from the app.
interface Context { token: Token | undefined; }
I think you can do the same and extend the plugin with a worktime script follows the same trick with a plugin entry point like this:
// app.ts
export interface Token {
sub?: string;
iss?: string;
aud?: string;
exp?: number;
iat?: number;
name?: string;
admin?: boolean;
}
use(auth<Token>({
appSecret: "<YOUR SECRET>" // required
}))
The worktime script has to use the ts compiler has to extract the signature and catch the generic type and generates a definition file extending NexusContext with an import of the Token interface.
I'm not sure if it's faisable, but it seems to ben the pattern in nexus framework : use worktime scripts to generate safety for the end user.
Hope this helps.
from nexus-plugin-jwt-auth.
In the meantime, simpler version to inject custom types to NexusContext:
interface Token {
sub?: string;
iss?: string;
aud?: string;
exp?: number;
iat?: number;
name?: string;
admin?: boolean;
}
declare global {
interface NexusContext extends Context {}
}
interface Context {
token: Token;
}
use(auth({
appSecret: "<YOUR SECRET>" // required
}))
from nexus-plugin-jwt-auth.
In the meantime, simpler version to inject custom types to NexusContext:
interface Token { sub?: string; iss?: string; aud?: string; exp?: number; iat?: number; name?: string; admin?: boolean; } declare global { interface NexusContext extends Context {} } interface Context { token: Token; } use(auth({ appSecret: "<YOUR SECRET>" // required }))
I have an issue with this saying:
Interface 'NexusContext' cannot simultaneously extend types 'Context' and 'Context'.
Named property ''token'' of types 'Context' and 'Context' are not identical.ts(2320)
when i try to put quotes around the token they get revoked but when i look into the index.d.ts on the typegen-nexus i see that there are quotes around the token which remain. Don't know what the magic behind this is...
from nexus-plugin-jwt-auth.
@zingerj Same here
from nexus-plugin-jwt-auth.
There is something like a read-only thing on the typegen-nexus @type... or its a bug... but i also tried to change the typegen js, removing the single quotes but without success, you simply aren't able to ammend the Context interface props... even not with a mapped type.
you can omit it using @ts-ignore or do smoething like this:
validUser = (ctx.token as unknown) as { userId: number }
i prefer the ts-ignore workaround
from nexus-plugin-jwt-auth.
Any news on this?
from nexus-plugin-jwt-auth.
Thanks @homerjam for PR #58 which gives a decent workaround for the time being! Release v1.4.0 includes his changes which adds a setting for declaring the token type as a string.
from nexus-plugin-jwt-auth.
Related Issues (10)
- Network error: {"errors":[{"message":"jwt malformed"}]} HOT 3
- Custom lib (or logic) HOT 5
- Cannot use GraphQLSchema "[object GraphQLSchema]" from another module or realm. HOT 1
- Unable to build nexus server HOT 1
- Update nexus-plugin-prisma in examples
- Wildcard Route Protection HOT 1
- Property ... does not exist on type 'string'. HOT 1
- Feature Request: Add testing example
- How to authenticate subscriptions?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nexus-plugin-jwt-auth.