Skip to content

Instantly share code, notes, and snippets.

@ferrerojosh
Last active July 10, 2023 20:03
Show Gist options
  • Save ferrerojosh/653500646a0debf01548d315fe61a773 to your computer and use it in GitHub Desktop.
Save ferrerojosh/653500646a0debf01548d315fe61a773 to your computer and use it in GitHub Desktop.
Keycloak v9.0.0 NestJS Resource Guard
import { FactoryProvider, Logger } from '@nestjs/common';
import Keycloak from 'keycloak-connect';
export const KEYCLOAK_INSTANCE = 'KEYCLOAK_INSTANCE';
export const keycloakProvider: FactoryProvider = {
provide: KEYCLOAK_INSTANCE,
useFactory: () => {
const keycloakConfig: any = {
realm: '',
clientId: '',
secret: '',
authServerUrl: '',
};
const keycloak: any = new Keycloak({}, keycloakConfig);
// We just need it to return next(false) so our guard will be able to latch on
keycloak.accessDenied = (req, res, next) => {
next(false);
};
return keycloak;
}
};
import { SetMetadata } from '@nestjs/common';
export const Permissions = (...permissions: string[]) =>
SetMetadata('permissions', permissions);
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
Logger,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import KeycloakConnect from 'keycloak-connect';
import { KEYCLOAK_INSTANCE } from './keycloak.provider';
@Injectable()
export class ResourceGuard implements CanActivate {
constructor(
@Inject(KEYCLOAK_INSTANCE)
private keycloak: KeycloakConnect.Keycloak,
private readonly reflector: Reflector,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const permissions = this.reflector.get<string[]>(
'permissions',
context.getHandler(),
);
const [request, response] = [
this.getRequest(context),
context.switchToHttp().getResponse(),
];
const enforcerFn = createEnforcerContext(request, response);
return await enforcerFn(this.keycloak, permissions);
}
getRequest<T = any>(context: ExecutionContext): T {
return context.switchToHttp().getRequest();
}
}
const createEnforcerContext = (
request,
response,
) => (keycloak: KeycloakConnect.Keycloak, permissions: string[]) =>
new Promise<boolean>((resolve, reject) =>
keycloak.enforcer(permissions)(request, response, next => {
if (next !== undefined) {
resolve(false);
} else {
resolve(true);
}
}),
);
@ferrerojosh
Copy link
Author

@ferrerojosh does it work with GraphQL?

It should, some guy made a PR for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment