Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

Commit

Permalink
♻️ Support referrer restrictions in API keys
Browse files Browse the repository at this point in the history
  • Loading branch information
AnandChowdhary committed Nov 8, 2020
1 parent d8a4cc9 commit 49ed4a4
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/modules/auth/auth.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface TotpTokenResponse {
export interface AccessTokenParsed {
id: number;
scopes: string[];
type: string;
type: 'user' | 'api-key';
}

export interface MfaTokenPayload {
Expand Down
44 changes: 32 additions & 12 deletions src/modules/auth/jwt.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Request } from 'express';
import { verify } from 'jsonwebtoken';
import { Strategy } from 'passport-strategy';
import { ApiKeysService } from '../api-keys/api-keys.service';
import { LOGIN_ACCESS_TOKEN } from '../tokens/tokens.constants';
import { AccessTokenClaims } from './auth.interface';
import { TokensService } from '../tokens/tokens.service';
import { AccessTokenClaims, AccessTokenParsed } from './auth.interface';
import minimatch from 'minimatch';

class StaartStrategy extends Strategy {
name = 'jwt';
}

@Injectable()
export class JwtStrategy extends PassportStrategy(StaartStrategy) {
constructor(private apiKeyService: ApiKeysService) {
constructor(
private apiKeyService: ApiKeysService,
private tokensService: TokensService,
) {
super();
}

private safeSuccess(result: AccessTokenParsed) {
return this.success(result);
}

async authenticate(request: Request) {
/** API key authorization */
let apiKey =
Expand All @@ -25,13 +33,26 @@ export class JwtStrategy extends PassportStrategy(StaartStrategy) {
request.headers.authorization;
if (typeof apiKey === 'string') {
if (apiKey.startsWith('Bearer ')) apiKey = apiKey.replace('Bearer ', '');
const apiKeyDetails = await this.apiKeyService.getApiKeyFromKey(apiKey);
if (apiKeyDetails)
return this.success({
try {
const apiKeyDetails = await this.apiKeyService.getApiKeyFromKey(apiKey);
const referer = request.headers.referer;
if (Array.isArray(apiKeyDetails.referrerRestrictions) && referer) {
let referrerRestrictionsMet = !apiKeyDetails.referrerRestrictions
.length;
apiKeyDetails.referrerRestrictions.forEach((restriction) => {
referrerRestrictionsMet =
referrerRestrictionsMet ||
minimatch(referer, restriction as string);
});
if (!referrerRestrictionsMet)
return this.fail('Referrer restrictions not met', 401);
}
return this.safeSuccess({
type: 'api-key',
id: apiKeyDetails.id,
scopes: apiKeyDetails.scopes,
scopes: apiKeyDetails.scopes as string[],
});
} catch (error) {}
}

/** Bearer JWT authorization */
Expand All @@ -41,15 +62,14 @@ export class JwtStrategy extends PassportStrategy(StaartStrategy) {
if (bearerToken.startsWith('Bearer '))
bearerToken = bearerToken.replace('Bearer ', '');
try {
const payload = verify(
const payload = this.tokensService.verify(
LOGIN_ACCESS_TOKEN,
bearerToken,
process.env.JWT_SECRET,
) as AccessTokenClaims;
const { sub, id, scopes } = payload;
if (sub !== LOGIN_ACCESS_TOKEN) throw new UnauthorizedException();
return this.success({ type: 'user', id, scopes });
return this.safeSuccess({ type: 'user', id, scopes });
} catch (error) {}

return this.fail('Unable to parse token', 401);
return this.fail('Invalid token', 401);
}
}

0 comments on commit 49ed4a4

Please sign in to comment.