Authorization
Authentication and Authorization are supported out of the box using @adonisjs/auth (authentication) and @adonisjs/bouncer (authorization).
You can find more information about Middlewares on the Official TypeGraphQL documentation
Secure operations
You can secure your queries to only allow authenticated users to use them by using the @Authorized decorator.
import from '#models/recipe'
import { , , , } from '@foadonis/graphql'
@()
class {
@(() => [])
@()
() {
// ...your logic
}
@(() => [])
@()
() {
// ...your logic
}
}The Authorized decorator accepts Bouncer abilities allowing you to ensure your user respects specific requirements.
import from '#models/recipe'
import { , , } from '@foadonis/graphql'
import from '#abilities/main'
@()
class {
@(() => [])
@(.isAdmin)
() {
// ...your logic
}
}import { } from '@adonisjs/bouncer'
const = {
: .(() => .isAdmin),
}
export default You can pass multiple abilities to @Authorized. The user will be authorized only if all of them
pass.
The @Authorized decorator can also be applied on a resolver class to protect all of its
operations. When an operation defines its own @Authorized, its rules replace the class-level
ones, they are not merged.
Using Policies
The Authorized decorator also accepts a Bouncer policy with the name of the method to use for authorization.
import from '#models/recipe'
import from '#policies/recipe_policy'
import { , , } from '@foadonis/graphql'
@()
class {
@(() => [])
@(, 'viewList')
() {
// ...your logic
}
}import from '#models/user'
import { } from '@adonisjs/bouncer'
import { } from '@adonisjs/bouncer/types'
export default class extends {
(: ): {
return .isAdmin
}
}Policies are resolved through the IoC container, so you can inject dependencies in them like anywhere else in your Adonis application.
Secure objects
The @Authorized decorator also works on fields allowing you to protect only certain fields.
With the following example, only authenticated user can access the fullName and only admins can access email.
import { , , } from '@foadonis/graphql'
import from '#abilities/main'
@()
export default class {
@()
declare : string
@()
@()
declare : string
@()
@(.isAdmin)
declare : string
}Accessing the object
When @Authorized protects a field (or a field resolver), the parent object is passed to the ability or policy method after the user. This allows authorization rules based on the object itself, like restricting a field to its owner:
import { , , } from '@foadonis/graphql'
import from '#policies/recipe_policy'
@()
export default class {
@()
declare : string
@()
@(, 'viewSecret')
declare : string
}import from '#models/user'
import from '#models/recipe'
import { } from '@adonisjs/bouncer'
import { } from '@adonisjs/bouncer/types'
export default class extends {
(: , : ): {
return .authorId === .id
}
}On queries and mutations there is no parent object: the ability or policy method receives
undefined instead. To authorize against an object that is not resolved yet, fetch it inside the
resolver and use ctx.bouncer directly.
Allowing guests
A bare @Authorized() always requires an authenticated user. When abilities or policies are provided, the decision is delegated to Bouncer: abilities and policy methods that allow guests are evaluated even when no user is logged in.
import { } from '@adonisjs/bouncer'
export const = .({ : true }, (, ) => {
return .isPublished || .authorId === ?.id
})A policy before hook
runs before the guest check. If it returns a truthy value for a null user, guests are
authorized for every method of the policy, including methods not marked with @allowGuest().
Access authenticated User
Using @CurrentUser
import from '#models/recipe'
import { , , } from '@foadonis/graphql'
@()
class {
@(() => [])
(@() : ) {
// ...your logic
}
}The @CurrentUser decorator makes your operation only available to authenticated users. If you
still want to allow guest, you must use the context.
Using the context
import from '#models/recipe'
import { } from '@adonisjs/core/http'
import { , , } from '@foadonis/graphql'
@()
class {
@(() => [])
(@() : ) {
const = .auth.getUserOrFail()
// ...your logic
}
}