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.

app/graphql/resolvers/recipe_resolver.ts
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.

app/models/user.ts
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.

app/abilities/main.ts
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

app/graphql/resolvers/recipe_resolver.ts
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

app/graphql/resolvers/recipe_resolver.ts
import  from '#models/recipe'
import {  } from '@adonisjs/core/http'
import { , ,  } from '@foadonis/graphql'

@()
class  {
  @(() => [])
  (@() : ) {
    const  = .auth.getUserOrFail()
    // ...your logic
  }
}

On this page