Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mercurius-auth

Package Overview
Dependencies
Maintainers
2
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mercurius-auth - npm Package Compare versions

Comparing version 1.3.1 to 1.4.0

docs/schema-filtering.md

1

docs/api/options.md

@@ -17,2 +17,3 @@ # mercurius-auth

* **filterSchema** `boolean` - when `true`, [introspection queries](https://graphql.org/learn/introspection/) will only return the parts of the schema which are accessible based on the applied policies.
### `external` mode

@@ -19,0 +20,0 @@

@@ -40,2 +40,3 @@ # Auth context

const app = Fastify()
app.register(mercurius, {

@@ -42,0 +43,0 @@ schema,

@@ -65,2 +65,6 @@ import { FastifyPluginAsync } from 'fastify'

authDirective: string;
/**
* When set to true, the plugin will automatically filter the output Schema during Introspection queries if the applyPolicy function is not satisfated.
*/
filterSchema?: boolean;
}

@@ -67,0 +71,0 @@

@@ -6,2 +6,3 @@ 'use strict'

const { validateOpts } = require('./lib/validation')
const filterSchema = require('./lib/filter-schema')

@@ -25,2 +26,5 @@ const plugin = fp(

auth.registerAuthHandlers(schema, authSchema)
if (opts.filterSchema === true) {
filterSchema.updatePolicy(app, authSchema, opts)
}
})

@@ -31,2 +35,6 @@

}
if (opts.filterSchema === true) {
filterSchema(app, authSchema, opts)
}
},

@@ -33,0 +41,0 @@ {

@@ -29,2 +29,6 @@ 'use strict'

}
if (opts.filterSchema === true) {
throw new MER_AUTH_ERR_INVALID_OPTS('opts.filterSchema cannot be used when mode is external.')
}
// Default mode

@@ -31,0 +35,0 @@ } else {

7

package.json
{
"name": "mercurius-auth",
"version": "1.3.1",
"version": "1.4.0",
"description": "Mercurius Auth Plugin adds configurable Authentication and Authorization support to Mercurius.",

@@ -41,3 +41,3 @@ "main": "index.js",

"fastify": "^3.0.2",
"mercurius": "^8.0.0",
"mercurius": "^8.10.0",
"pre-commit": "^1.2.2",

@@ -47,3 +47,3 @@ "snazzy": "^9.0.0",

"tap": "^15.0.2",
"tsd": "^0.18.0",
"tsd": "^0.19.0",
"typescript": "^4.0.3",

@@ -53,2 +53,3 @@ "wait-on": "^6.0.0"

"dependencies": {
"@graphql-tools/wrap": "^8.3.2",
"fastify-error": "^0.3.0",

@@ -55,0 +56,0 @@ "fastify-plugin": "^3.0.0",

@@ -28,2 +28,3 @@ # mercurius-auth

- [Auth Directive](docs/auth-directive.md)
- [Schema filtering](docs/schema-filtering.md)
- [External Policy](docs/external-policy.md)

@@ -30,0 +31,0 @@ - [Errors](docs/errors.md)

@@ -442,1 +442,49 @@ 'use strict'

})
test('gateway - should filter the schema output', async (t) => {
t.plan(4)
const order = [
'topPosts',
'name',
'author'
]
const app = await createTestGatewayServer(t, {
filterSchema: true,
async applyPolicy (authDirectiveAST, parent, args, context, info) {
t.equal(info.fieldName, order.shift())
return false
},
authDirective: 'auth'
})
const query = `{
__type(name: "Query") {
name
fields {
name
}
}
}`
const res = await app.inject({
method: 'POST',
headers: { 'content-type': 'application/json', 'x-user': 'admin' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.same(res.json(), {
data: {
__type: {
name: 'Query',
fields: [
{
name: 'me'
}
]
}
}
})
})

@@ -195,1 +195,245 @@ 'use strict'

})
test('polling a filtered schema should complete the refresh succesfully', async (t) => {
t.plan(8)
const clock = FakeTimers.install({
shouldAdvanceTime: true,
advanceTimeDelta: 40
})
t.teardown(() => clock.uninstall())
const user = {
id: 'u1',
name: 'John',
lastName: 'Doe'
}
const resolvers = {
Query: {
me: (root, args, context, info) => user
},
User: {
__resolveReference: (user, args, context, info) => user
}
}
const userService = Fastify()
const gateway = Fastify()
t.teardown(async () => {
await gateway.close()
await userService.close()
})
userService.register(mercurius, {
schema: `
directive @auth on OBJECT | FIELD_DEFINITION
extend type Query {
me: User
}
type User @key(fields: "id") {
id: ID!
name: String @auth
}
`,
resolvers: resolvers,
federationMetadata: true
})
await userService.listen(0)
const userServicePort = userService.server.address().port
await gateway.register(mercurius, {
gateway: {
services: [
{
name: 'user',
url: `http://localhost:${userServicePort}/graphql`
}
],
pollingInterval: 2000
}
})
await gateway.register(mercuriusAuth, {
filterSchema: true,
authContext (context) {
return {
identity: context.reply.request.headers['x-user']
}
},
async applyPolicy (authDirectiveAST, parent, args, context, info) {
t.ok('should be called')
return context.auth.identity === 'admin'
},
authDirective: 'auth'
})
{
const query = `query {
me {
id
name
}
}`
const res = await gateway.inject({
method: 'POST',
headers: { 'content-type': 'application/json', 'x-user': 'user' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.same(JSON.parse(res.body), {
data: {
me: {
id: 'u1',
name: null
}
},
errors: [
{
message: 'Failed auth policy check on name',
locations: [
{
line: 4,
column: 7
}
],
path: [
'me',
'name'
]
}
]
})
}
{
const query = `{
__type(name:"User"){
name
fields{
name
}
}
}`
const res = await gateway.inject({
method: 'POST',
headers: { 'content-type': 'application/json', 'x-user': 'user' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.same(res.json(), {
data: {
__type: {
name: 'User',
fields: [
{ name: 'id' }
]
}
}
})
}
userService.graphql.replaceSchema(
mercurius.buildFederationSchema(`
directive @auth on OBJECT | FIELD_DEFINITION
extend type Query {
me: User
}
type User @key(fields: "id") {
id: ID!
name: String
lastName: String @auth
}
`)
)
userService.graphql.defineResolvers(resolvers)
await clock.tickAsync(2000)
// We need the event loop to actually spin twice to
// be able to propagate the change
await immediate()
await immediate()
{
const query = `query {
me {
id
name
lastName
}
}`
const res = await gateway.inject({
method: 'POST',
headers: { 'content-type': 'application/json', 'x-user': 'user' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.same(JSON.parse(res.body), {
data: {
me: {
id: 'u1',
name: 'John',
lastName: null
}
},
errors: [
{
message: 'Failed auth policy check on lastName',
locations: [
{
line: 5,
column: 7
}
],
path: [
'me',
'lastName'
]
}
]
})
}
{
const query = `{
__type(name:"User"){
name
fields{
name
}
}
}`
const res = await gateway.inject({
method: 'POST',
headers: { 'content-type': 'application/json', 'x-user': 'user' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.same(res.json(), {
data: {
__type: {
name: 'User',
fields: [
{ name: 'id' },
{ name: 'name' }
]
}
}
})
}
})

@@ -141,3 +141,3 @@ 'use strict'

test('registration - external policy', t => {
t.plan(3)
t.plan(4)

@@ -204,2 +204,19 @@ t.test('should error if policy is not an object', async (t) => {

})
t.test('cannot filter introspection schema on external mode', async (t) => {
t.plan(1)
const app = Fastify()
t.teardown(app.close.bind(app))
app.register(mercurius, {
schema,
resolvers
})
await t.rejects(app.register(mercuriusAuth, {
applyPolicy: () => {},
mode: 'external',
filterSchema: true
}), new MER_AUTH_ERR_INVALID_OPTS('opts.filterSchema cannot be used when mode is external.'))
})
})

@@ -44,2 +44,3 @@ import { expectAssignable, expectType } from 'tsd'

const authOptions: MercuriusAuthOptions = {
filterSchema: true,
authDirective: 'auth',

@@ -46,0 +47,0 @@ async applyPolicy (

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc