Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
porcellus committed Sep 22, 2024
1 parent 374f066 commit 0423ce8
Show file tree
Hide file tree
Showing 19 changed files with 157 additions and 97 deletions.
8 changes: 4 additions & 4 deletions lib/build/recipe/oauth2client/recipeImplementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ function getRecipeImplementation(_querier, config) {
};
},
getProviderConfig: async function ({ clientId }) {
if (providerConfigsWithOIDCInfo[clientId] !== null) {
if (providerConfigsWithOIDCInfo[clientId] !== undefined) {
return providerConfigsWithOIDCInfo[clientId];
}
console.log("config.providerConfigs", config.providerConfigs, clientId);
const providerConfig = config.providerConfigs.find(
(providerConfig) => providerConfig.clientId === clientId
);
const oidcInfo = await thirdpartyUtils_1.getOIDCDiscoveryInfo(
config.providerConfigs[0].oidcDiscoveryEndpoint
);
console.log("providerConfig", providerConfig);
const oidcInfo = await thirdpartyUtils_1.getOIDCDiscoveryInfo(providerConfig.oidcDiscoveryEndpoint);
if (oidcInfo.authorization_endpoint === undefined) {
throw new Error("Failed to authorization_endpoint from the oidcDiscoveryEndpoint.");
}
Expand Down
2 changes: 1 addition & 1 deletion lib/build/recipe/oauth2client/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function validateAndNormaliseUserInput(_appInfo, config) {
if (config.providerConfigs.some((providerConfig) => providerConfig.clientId === undefined)) {
throw new Error("Please pass clientId for all providerConfigs.");
}
if (!config.providerConfigs.every((providerConfig) => providerConfig.clientId.startsWith("supertokens_"))) {
if (!config.providerConfigs.every((providerConfig) => providerConfig.clientId.startsWith("stcl_"))) {
throw new Error(
`Only Supertokens OAuth ClientIds are supported in the OAuth2Client recipe. For any other OAuth Clients use the ThirdParty recipe.`
);
Expand Down
7 changes: 7 additions & 0 deletions lib/build/recipe/oauth2provider/api/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const set_cookie_parser_1 = __importDefault(require("set-cookie-parser"));
const session_1 = __importDefault(require("../../session"));
const error_1 = __importDefault(require("../../../recipe/session/error"));
async function authGET(apiImplementation, options, userContext) {
var _a;
if (apiImplementation.authGET === undefined) {
return false;
}
Expand Down Expand Up @@ -72,6 +73,12 @@ async function authGET(apiImplementation, options, userContext) {
}
}
options.res.original.redirect(response.redirectTo);
} else if ("statusCode" in response) {
utils_1.sendNon200ResponseWithMessage(
options.res,
response.error + ": " + response.errorDescription,
(_a = response.statusCode) !== null && _a !== void 0 ? _a : 400
);
} else {
utils_1.send200Response(options.res, response);
}
Expand Down
3 changes: 3 additions & 0 deletions lib/build/recipe/oauth2provider/api/implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ function getAPIImplementation() {
session,
userContext,
});
if ("error" in response) {
return response;
}
return utils_1.handleLoginInternalRedirects({
response,
recipeImplementation: options.recipeImplementation,
Expand Down
14 changes: 10 additions & 4 deletions lib/build/recipe/oauth2provider/api/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const session_1 = __importDefault(require("../../session"));
const error_1 = __importDefault(require("../../../error"));
const error_2 = __importDefault(require("../../../recipe/session/error"));
async function login(apiImplementation, options, userContext) {
var _a;
var _a, _b;
if (apiImplementation.loginGET === undefined) {
return false;
}
Expand Down Expand Up @@ -60,9 +60,7 @@ async function login(apiImplementation, options, userContext) {
shouldTryRefresh,
userContext,
});
if ("status" in response) {
utils_1.send200Response(options.res, response);
} else {
if ("redirectTo" in response) {
if (response.setCookie) {
const cookieStr = set_cookie_parser_1.default.splitCookiesString(response.setCookie);
const cookies = set_cookie_parser_1.default.parse(cookieStr);
Expand All @@ -80,6 +78,14 @@ async function login(apiImplementation, options, userContext) {
}
}
options.res.original.redirect(response.redirectTo);
} else if ("statusCode" in response) {
utils_1.sendNon200ResponseWithMessage(
options.res,
response.error + ": " + response.errorDescription,
(_b = response.statusCode) !== null && _b !== void 0 ? _b : 400
);
} else {
utils_1.send200Response(options.res, response);
}
return true;
}
Expand Down
13 changes: 8 additions & 5 deletions lib/build/recipe/oauth2provider/api/utils.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-nocheck
import { UserContext } from "../../../types";
import { SessionContainerInterface } from "../../session/types";
import { RecipeInterface } from "../types";
import { ErrorOAuth2, RecipeInterface } from "../types";
export declare function loginGET({
recipeImplementation,
loginChallenge,
Expand Down Expand Up @@ -39,10 +39,13 @@ export declare function handleLoginInternalRedirects({
shouldTryRefresh: boolean;
cookie?: string;
userContext: UserContext;
}): Promise<{
redirectTo: string;
setCookie?: string;
}>;
}): Promise<
| {
redirectTo: string;
setCookie?: string;
}
| ErrorOAuth2
>;
export declare function handleLogoutInternalRedirects({
response,
recipeImplementation,
Expand Down
7 changes: 5 additions & 2 deletions lib/build/recipe/oauth2provider/api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ async function loginGET({
})
.getAsStringDangerous();
const websiteBasePath = appInfo.websiteBasePath.getAsStringDangerous();
console.log({ n: "loginGET2", shouldTryRefresh });
if (shouldTryRefresh) {
if (shouldTryRefresh && promptParam !== "login") {
const websiteDomain = appInfo
.getOrigin({
request: undefined,
Expand Down Expand Up @@ -246,6 +245,9 @@ async function handleLoginInternalRedirects({
session,
userContext,
});
if ("error" in authRes) {
return authRes;
}
response = {
redirectTo: authRes.redirectTo,
setCookie: mergeSetCookieHeaders(authRes.setCookie, response.setCookie),
Expand All @@ -255,6 +257,7 @@ async function handleLoginInternalRedirects({
}
redirectCount++;
}
console.log("handleLoginInternalRedirects3", response);
return response;
}
exports.handleLoginInternalRedirects = handleLoginInternalRedirects;
Expand Down
10 changes: 2 additions & 8 deletions lib/build/recipe/oauth2provider/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,20 +221,14 @@ class Recipe extends recipeModule_1.default {
if (sessionInfo === undefined) {
throw new Error("Session not found");
}
let payload = {
tId: sessionInfo.tenantId,
rsub: sessionInfo.recipeUserId.getAsString(),
sessionHandle: sessionHandle,
};
let payload = {};
for (const fn of this.accessTokenBuilders) {
payload = Object.assign(Object.assign({}, payload), await fn(user, scopes, sessionHandle, userContext));
}
return payload;
}
async getDefaultIdTokenPayload(user, scopes, sessionHandle, userContext) {
let payload = {
iss: this.appInfo.apiDomain.getAsStringDangerous() + this.appInfo.apiBasePath.getAsStringDangerous(),
};
let payload = {};
if (scopes.includes("email")) {
payload.email = user === null || user === void 0 ? void 0 : user.emails[0];
payload.email_verified = user.loginMethods.some(
Expand Down
63 changes: 35 additions & 28 deletions lib/build/recipe/oauth2provider/recipeImplementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,17 @@ function getRecipeInterface(
rejectLoginRequest: async function (input) {
const resp = await querier.sendPutRequest(
new normalisedURLPath_1.default(`/recipe/oauth/auth/requests/login/reject`),
copyAndCleanRequestBodyInput(input),
{
loginChallenge: input.challenge,
error: input.error.error,
errorDescription: input.error.errorDescription,
statusCode: input.error.statusCode,
},
{
login_challenge: input.challenge,
},
input.userContext
);
console.log("rejectLoginRequest resp", resp);
return {
// TODO: FIXME!!!
redirectTo: getUpdatedRedirectTo(appInfo, resp.redirectTo),
Expand Down Expand Up @@ -225,11 +230,10 @@ function getRecipeInterface(
},
authorization: async function (input) {
var _a, _b, _c, _d;
if (input.session !== undefined) {
if (input.params.prompt === "none") {
input.params["st_prompt"] = "none";
delete input.params.prompt;
}
// we handle this in the backend SDK level
if (input.params.prompt === "none") {
input.params["st_prompt"] = "none";
delete input.params.prompt;
}
let payloads;
if (input.params.client_id === undefined) {
Expand Down Expand Up @@ -288,6 +292,13 @@ function getRecipeInterface(
},
input.userContext
);
if (resp.status !== "OK") {
return {
statusCode: resp.statusCode,
error: resp.error,
errorDescription: resp.errorDescription,
};
}
const redirectTo = getUpdatedRedirectTo(appInfo, resp.redirectTo);
if (redirectTo === undefined) {
throw new Error(resp.body);
Expand Down Expand Up @@ -380,7 +391,7 @@ function getRecipeInterface(
});
console.log("tokenInfo", input.body.refresh_token, tokenInfo);
if (tokenInfo.active === true) {
const sessionHandle = tokenInfo.ext.sessionHandle;
const sessionHandle = tokenInfo.sessionHandle;
const clientInfo = await this.getOAuth2Client({
clientId: tokenInfo.client_id,
userContext: input.userContext,
Expand Down Expand Up @@ -420,27 +431,30 @@ function getRecipeInterface(
if (input.authorizationHeader) {
body["authorizationHeader"] = input.authorizationHeader;
}
console.log("/recipe/oauth/token", body);
const res = await querier.sendPostRequest(
new normalisedURLPath_1.default(`/recipe/oauth/token`),
body,
input.userContext
);
console.log("/recipe/oauth/token", body, res);
if (res.status !== "OK") {
return {
statusCode: res.statusCode,
error: res.error,
errorDescription: res.error_description,
errorDescription: res.errorDescription,
};
}
return res;
},
getOAuth2Clients: async function (input) {
let response = await querier.sendGetRequestWithResponseHeaders(
new normalisedURLPath_1.default(`/recipe/oauth/clients`),
Object.assign(Object.assign({}, copyAndCleanRequestBodyInput(input)), {
new normalisedURLPath_1.default(`/recipe/oauth/clients/list`),
{
pageSize: input.pageSize,
clientName: input.clientName,
owner: input.owner,
pageToken: input.paginationToken,
}),
},
{},
input.userContext
);
Expand Down Expand Up @@ -543,7 +557,7 @@ function getRecipeInterface(
return getDefaultUserInfoPayload(user, accessTokenPayload, scopes, tenantId, userContext);
},
validateOAuth2AccessToken: async function (input) {
var _a, _b, _c, _d, _e, _f, _g, _h;
var _a, _b, _c, _d, _e;
const payload = (await jose.jwtVerify(input.token, combinedRemoteJWKSet_1.getCombinedJWKS())).payload;
if (payload.stt !== 1) {
throw new Error("Wrong token type");
Expand All @@ -552,7 +566,9 @@ function getRecipeInterface(
((_a = input.requirements) === null || _a === void 0 ? void 0 : _a.clientId) !== undefined &&
payload.client_id !== input.requirements.clientId
) {
throw new Error("The token doesn't belong to the specified client");
throw new Error(
`The token doesn't belong to the specified client (${input.requirements.clientId} !== ${payload.client_id})`
);
}
if (
((_b = input.requirements) === null || _b === void 0 ? void 0 : _b.scopes) !== undefined &&
Expand All @@ -578,19 +594,11 @@ function getRecipeInterface(
new normalisedURLPath_1.default(`/recipe/oauth/introspect`),
{
token: input.token,
scope:
(_h =
(_g = (_f = input.requirements) === null || _f === void 0 ? void 0 : _f.scopes) ===
null || _g === void 0
? void 0
: _g.join(" ")) !== null && _h !== void 0
? _h
: undefined,
},
input.userContext
);
if (response.status !== "OK" || response.active !== true) {
throw new Error(response.error);
if (response.active !== true) {
throw new Error("The token is expired, invalid or has been revoked");
}
}
return { status: "OK", payload: payload };
Expand Down Expand Up @@ -618,7 +626,7 @@ function getRecipeInterface(
return {
statusCode: res.statusCode,
error: res.error,
errorDescription: res.error_description,
errorDescription: res.errorDescription,
};
}
return { status: "OK" };
Expand Down Expand Up @@ -714,8 +722,7 @@ function getRecipeInterface(
input.userContext
);
return {
// TODO: FIXME!!!
redirectTo: getUpdatedRedirectTo(appInfo, resp.redirect_to)
redirectTo: getUpdatedRedirectTo(appInfo, resp.redirectTo)
// NOTE: This renaming only applies to this endpoint, hence not part of the generic "getUpdatedRedirectTo" function.
.replace("/sessions/logout", "/end_session"),
};
Expand Down
12 changes: 8 additions & 4 deletions lib/build/recipe/oauth2provider/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,13 @@ export declare type RecipeInterface = {
cookies: string | undefined;
session: SessionContainerInterface | undefined;
userContext: UserContext;
}): Promise<{
redirectTo: string;
setCookie: string | undefined;
}>;
}): Promise<
| {
redirectTo: string;
setCookie: string | undefined;
}
| ErrorOAuth2
>;
tokenExchange(input: {
authorizationHeader?: string;
body: Record<string, string | undefined>;
Expand Down Expand Up @@ -321,6 +324,7 @@ export declare type APIInterface = {
redirectTo: string;
setCookie?: string;
}
| ErrorOAuth2
| GeneralErrorResponse
>);
authGET:
Expand Down
6 changes: 4 additions & 2 deletions lib/ts/recipe/oauth2client/recipeImplementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,15 @@ export default function getRecipeImplementation(_querier: Querier, config: TypeN
};
},
getProviderConfig: async function ({ clientId }) {
if (providerConfigsWithOIDCInfo[clientId] !== null) {
if (providerConfigsWithOIDCInfo[clientId] !== undefined) {
return providerConfigsWithOIDCInfo[clientId];
}
console.log("config.providerConfigs", config.providerConfigs, clientId);
const providerConfig = config.providerConfigs.find(
(providerConfig) => providerConfig.clientId === clientId
)!;
const oidcInfo = await getOIDCDiscoveryInfo(config.providerConfigs[0].oidcDiscoveryEndpoint);
console.log("providerConfig", providerConfig);
const oidcInfo = await getOIDCDiscoveryInfo(providerConfig.oidcDiscoveryEndpoint);

if (oidcInfo.authorization_endpoint === undefined) {
throw new Error("Failed to authorization_endpoint from the oidcDiscoveryEndpoint.");
Expand Down
2 changes: 1 addition & 1 deletion lib/ts/recipe/oauth2client/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function validateAndNormaliseUserInput(_appInfo: NormalisedAppinfo, confi
throw new Error("Please pass clientId for all providerConfigs.");
}

if (!config.providerConfigs.every((providerConfig) => providerConfig.clientId.startsWith("supertokens_"))) {
if (!config.providerConfigs.every((providerConfig) => providerConfig.clientId.startsWith("stcl_"))) {
throw new Error(
`Only Supertokens OAuth ClientIds are supported in the OAuth2Client recipe. For any other OAuth Clients use the ThirdParty recipe.`
);
Expand Down
Loading

0 comments on commit 0423ce8

Please sign in to comment.