Authentication & Authorization — GraphQL

Auth di GraphQL Authentication (siapa kamu?) biasanya di transport layer (HTTP header). Authorization (boleh akses apa?) di resolver atau directive level. Authe

Auth di GraphQL

Authentication (siapa kamu?) biasanya di transport layer (HTTP header). Authorization (boleh akses apa?) di resolver atau directive level.

Authentication via Context

// Server setup
context: async ({ req }) => {
  const token = req.headers.authorization?.replace("Bearer ", "");
  let user = null;

  if (token) {
    try {
      user = await verifyToken(token);
    } catch {
      // Token invalid — user tetap null
    }
  }

  return { user, db: prisma };
}

Authorization di Resolver

const resolvers = {
  Query: {
    me: (_, __, { user }) => {
      if (!user) throw new GraphQLError("Not authenticated", {
        extensions: { code: "UNAUTHENTICATED" },
      });
      return user;
    },

    adminDashboard: (_, __, { user }) => {
      if (!user) throw new GraphQLError("Not authenticated");
      if (user.role !== "ADMIN") throw new GraphQLError("Not authorized", {
        extensions: { code: "FORBIDDEN" },
      });
      return getDashboardData();
    },
  },
};

Auth Directive

# Schema
directive @auth(requires: Role = VIEWER) on FIELD_DEFINITION

type Query {
  publicPosts: [Post!]!
  me: User! @auth
  adminStats: Stats! @auth(requires: ADMIN)
}

// Directive implementation
class AuthDirective extends SchemaDirectiveVisitor {
  visitFieldDefinition(field) {
    const requiredRole = this.args.requires;
    const { resolve } = field;

    field.resolve = async function (...args) {
      const context = args[2];
      if (!context.user) throw new GraphQLError("Not authenticated");
      if (requiredRole && context.user.role !== requiredRole) {
        throw new GraphQLError("Not authorized");
      }
      return resolve.apply(this, args);
    };
  }
}

Field-level Authorization

// User bisa lihat profile sendiri, tapi email hanya visible untuk admin
User: {
  email: (parent, _, { user }) => {
    if (user.id === parent.id || user.role === "ADMIN") {
      return parent.email;
    }
    return null; // Hide email
  },
}

Yang akan kamu pelajari