Skip to content

Commit

Permalink
feat: Add token revocation endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
anku255 committed Jul 31, 2024
1 parent a351c0a commit daa4df5
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 1 deletion.
7 changes: 7 additions & 0 deletions lib/build/recipe/oauth2provider/api/implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ function getAPIImplementation() {
userContext,
});
},
revokeTokenPOST: async (input) => {
return input.options.recipeImplementation.revokeToken({
token: input.body.token,
tokenTypeHint: input.body.tokenTypeHint,
userContext: input.userContext,
});
},
};
}
exports.default = getAPIImplementation;
8 changes: 8 additions & 0 deletions lib/build/recipe/oauth2provider/api/revokeToken.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @ts-nocheck
import { APIInterface, APIOptions } from "..";
import { UserContext } from "../../../types";
export default function revokeTokenPOST(
apiImplementation: APIInterface,
options: APIOptions,
userContext: UserContext
): Promise<boolean>;
38 changes: 38 additions & 0 deletions lib/build/recipe/oauth2provider/api/revokeToken.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use strict";
/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
*
* This software is licensed under the Apache License, Version 2.0 (the
* "License") as published by the Apache Software Foundation.
*
* You may not use this file except in compliance with the License. You may
* obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../../../utils");
async function revokeTokenPOST(apiImplementation, options, userContext) {
if (apiImplementation.revokeTokenPOST === undefined) {
return false;
}
const body = await options.req.getJSONBody();
if (body.token === undefined) {
utils_1.sendNon200ResponseWithMessage(options.res, "token is required in the request body", 400);
return true;
}
let response = await apiImplementation.revokeTokenPOST({
options,
body: {
token: body.token,
tokenTypeHint: body.token_type_hint,
},
userContext,
});
utils_1.send200Response(options.res, response);
return true;
}
exports.default = revokeTokenPOST;
1 change: 1 addition & 0 deletions lib/build/recipe/oauth2provider/constants.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export declare const AUTH_PATH = "/oauth2provider/auth";
export declare const TOKEN_PATH = "/oauth2provider/token";
export declare const LOGIN_INFO_PATH = "/oauth2provider/login/info";
export declare const USER_INFO_PATH = "/oauth2provider/userinfo";
export declare const REVOKE_TOKEN_PATH = "/oauth2provider/token/revoke";
3 changes: 2 additions & 1 deletion lib/build/recipe/oauth2provider/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
* under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.USER_INFO_PATH = exports.LOGIN_INFO_PATH = exports.TOKEN_PATH = exports.AUTH_PATH = exports.LOGIN_PATH = exports.OAUTH2_BASE_PATH = void 0;
exports.REVOKE_TOKEN_PATH = exports.USER_INFO_PATH = exports.LOGIN_INFO_PATH = exports.TOKEN_PATH = exports.AUTH_PATH = exports.LOGIN_PATH = exports.OAUTH2_BASE_PATH = void 0;
exports.OAUTH2_BASE_PATH = "/oauth2provider/";
exports.LOGIN_PATH = "/oauth2provider/login";
exports.AUTH_PATH = "/oauth2provider/auth";
exports.TOKEN_PATH = "/oauth2provider/token";
exports.LOGIN_INFO_PATH = "/oauth2provider/login/info";
exports.USER_INFO_PATH = "/oauth2provider/userinfo";
exports.REVOKE_TOKEN_PATH = "/oauth2provider/token/revoke";
10 changes: 10 additions & 0 deletions lib/build/recipe/oauth2provider/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ export default class Wrapper {
status: "OK";
payload: import("../usermetadata").JSONObject;
}>;
static revokeToken(
token: string,
tokenTypeHint?: "access_token" | "refresh_token",
userContext?: Record<string, any>
): Promise<
| import("../../types").GeneralErrorResponse
| {
status: "OK";
}
>;
}
export declare let init: typeof Recipe.init;
export declare let getOAuth2Clients: typeof Wrapper.getOAuth2Clients;
Expand Down
7 changes: 7 additions & 0 deletions lib/build/recipe/oauth2provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ class Wrapper {
userContext: utils_1.getUserContext(userContext),
});
}
static revokeToken(token, tokenTypeHint, userContext) {
return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.revokeToken({
token,
tokenTypeHint,
userContext: utils_1.getUserContext(userContext),
});
}
}
exports.default = Wrapper;
Wrapper.init = recipe_1.default.init;
Expand Down
12 changes: 12 additions & 0 deletions lib/build/recipe/oauth2provider/recipeImplementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,18 @@ function getRecipeInterface(querier, _config, appInfo, getDefaultIdTokenPayload,
// TODO: add a check to make sure this is the right token type as they can be signed with the same key
return { status: "OK", payload: payload };
},
revokeToken: async function ({ token, tokenTypeHint, userContext }) {
// TODO: Update the endpoint to the correct token revocation endpoint
const res = await querier.sendPostRequest(
new normalisedURLPath_1.default(`/recipe/oauth2/revoke/token`),
{
token,
tokenTypeHint,
},
userContext
);
return res.data;
},
};
}
exports.default = getRecipeInterface;
25 changes: 25 additions & 0 deletions lib/build/recipe/oauth2provider/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ export declare type RecipeInterface = {
tenantId: string;
userContext: UserContext;
}): Promise<JSONObject>;
revokeToken(input: {
token: string;
tokenTypeHint?: "access_token" | "refresh_token";
userContext: UserContext;
}): Promise<
| {
status: "OK";
}
| GeneralErrorResponse
>;
};
export declare type APIInterface = {
loginGET:
Expand Down Expand Up @@ -309,6 +319,21 @@ export declare type APIInterface = {
options: APIOptions;
userContext: UserContext;
}) => Promise<JSONObject | GeneralErrorResponse>);
revokeTokenPOST:
| undefined
| ((input: {
body: {
token: string;
tokenTypeHint?: "access_token" | "refresh_token";
};
options: APIOptions;
userContext: UserContext;
}) => Promise<
| {
status: "OK";
}
| GeneralErrorResponse
>);
};
export declare type OAuth2ClientOptions = {
clientId: string;
Expand Down
7 changes: 7 additions & 0 deletions lib/ts/recipe/oauth2provider/api/implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,12 @@ export default function getAPIImplementation(): APIInterface {
userContext,
});
},
revokeTokenPOST: async (input) => {
return input.options.recipeImplementation.revokeToken({
token: input.body.token,
tokenTypeHint: input.body.tokenTypeHint,
userContext: input.userContext,
});
},
};
}
47 changes: 47 additions & 0 deletions lib/ts/recipe/oauth2provider/api/revokeToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
*
* This software is licensed under the Apache License, Version 2.0 (the
* "License") as published by the Apache Software Foundation.
*
* You may not use this file except in compliance with the License. You may
* obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

import { send200Response, sendNon200ResponseWithMessage } from "../../../utils";
import { APIInterface, APIOptions } from "..";
import { UserContext } from "../../../types";

export default async function revokeTokenPOST(
apiImplementation: APIInterface,
options: APIOptions,
userContext: UserContext
): Promise<boolean> {
if (apiImplementation.revokeTokenPOST === undefined) {
return false;
}

const body = await options.req.getJSONBody();

if (body.token === undefined) {
sendNon200ResponseWithMessage(options.res, "token is required in the request body", 400);
return true;
}

let response = await apiImplementation.revokeTokenPOST({
options,
body: {
token: body.token,
tokenTypeHint: body.token_type_hint,
},
userContext,
});

send200Response(options.res, response);
return true;
}
1 change: 1 addition & 0 deletions lib/ts/recipe/oauth2provider/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export const AUTH_PATH = "/oauth2provider/auth";
export const TOKEN_PATH = "/oauth2provider/token";
export const LOGIN_INFO_PATH = "/oauth2provider/login/info";
export const USER_INFO_PATH = "/oauth2provider/userinfo";
export const REVOKE_TOKEN_PATH = "/oauth2provider/token/revoke";
12 changes: 12 additions & 0 deletions lib/ts/recipe/oauth2provider/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ export default class Wrapper {
userContext: getUserContext(userContext),
});
}

static revokeToken(
token: string,
tokenTypeHint?: "access_token" | "refresh_token",
userContext?: Record<string, any>
) {
return Recipe.getInstanceOrThrowError().recipeInterfaceImpl.revokeToken({
token,
tokenTypeHint,
userContext: getUserContext(userContext),
});
}
}

export let init = Wrapper.init;
Expand Down
13 changes: 13 additions & 0 deletions lib/ts/recipe/oauth2provider/recipeImplementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,5 +428,18 @@ export default function getRecipeInterface(

return { status: "OK", payload: payload as JSONObject };
},

revokeToken: async function (this: RecipeInterface, { token, tokenTypeHint, userContext }) {
// TODO: Update the endpoint to the correct token revocation endpoint
const res = await querier.sendPostRequest(
new NormalisedURLPath(`/recipe/oauth2/revoke/token`),
{
token,
tokenTypeHint,
},
userContext
);
return res.data;
},
};
}
15 changes: 15 additions & 0 deletions lib/ts/recipe/oauth2provider/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,11 @@ export type RecipeInterface = {
tenantId: string;
userContext: UserContext;
}): Promise<JSONObject>;
revokeToken(input: {
token: string;
tokenTypeHint?: "access_token" | "refresh_token";
userContext: UserContext;
}): Promise<{ status: "OK" } | GeneralErrorResponse>;
};

export type APIInterface = {
Expand Down Expand Up @@ -404,6 +409,16 @@ export type APIInterface = {
options: APIOptions;
userContext: UserContext;
}) => Promise<JSONObject | GeneralErrorResponse>);
revokeTokenPOST:
| undefined
| ((input: {
body: {
token: string;
tokenTypeHint?: "access_token" | "refresh_token";
};
options: APIOptions;
userContext: UserContext;
}) => Promise<{ status: "OK" } | GeneralErrorResponse>);
};

export type OAuth2ClientOptions = {
Expand Down

0 comments on commit daa4df5

Please sign in to comment.