Skip to content

Commit

Permalink
feat: update how oauth token payloads work
Browse files Browse the repository at this point in the history
  • Loading branch information
porcellus committed Sep 24, 2024
1 parent 376128a commit ce33439
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 82 deletions.
95 changes: 52 additions & 43 deletions lib/build/recipe/oauth2provider/recipeImplementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ function getRecipeInterface(
tId: input.tenantId,
rsub: input.rsub,
sessionHandle: input.sessionHandle,
initialAccessTokenPayload: input.initialAccessTokenPayload,
initialIdTokenPayload: input.initialIdTokenPayload,
},
{
consentChallenge: input.challenge,
Expand Down Expand Up @@ -205,25 +207,33 @@ function getRecipeInterface(
};
},
authorization: async function (input) {
var _a, _b, _c, _d;
var _a, _b, _c, _d, _e;
// 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) {
throw new Error("client_id is required");
if (input.params.client_id === undefined || typeof input.params.client_id !== "string") {
return {
statusCode: 400,
error: "invalid_request",
errorDescription: "client_id is required and must be a string",
};
}
const scopes = await this.getRequestedScopes({
scopeParam: ((_a = input.params.scope) === null || _a === void 0 ? void 0 : _a.split(" ")) || [],
clientId: input.params.client_id,
recipeUserId: (_b = input.session) === null || _b === void 0 ? void 0 : _b.getRecipeUserId(),
sessionHandle: (_c = input.session) === null || _c === void 0 ? void 0 : _c.getHandle(),
userContext: input.userContext,
});
const responseTypes =
(_b = (_a = input.params.response_type) === null || _a === void 0 ? void 0 : _a.split(" ")) !== null &&
_b !== void 0
? _b
(_e = (_d = input.params.response_type) === null || _d === void 0 ? void 0 : _d.split(" ")) !== null &&
_e !== void 0
? _e
: [];
if (
input.session !== undefined &&
(responseTypes.includes("token") || responseTypes.includes("id_token"))
) {
if (input.session !== undefined) {
const clientInfo = await this.getOAuth2Client({
clientId: input.params.client_id,
userContext: input.userContext,
Expand All @@ -236,24 +246,26 @@ function getRecipeInterface(
if (!user) {
throw new Error("User not found");
}
const idToken = responseTypes.includes("id_token")
? await this.buildIdTokenPayload({
user,
client,
sessionHandle: input.session.getHandle(),
scopes: ((_c = input.params.scope) === null || _c === void 0 ? void 0 : _c.split(" ")) || [],
userContext: input.userContext,
})
: undefined;
const accessToken = responseTypes.includes("token")
? await this.buildAccessTokenPayload({
user,
client,
sessionHandle: input.session.getHandle(),
scopes: ((_d = input.params.scope) === null || _d === void 0 ? void 0 : _d.split(" ")) || [],
userContext: input.userContext,
})
: undefined;
const idToken =
responseTypes.includes("id_token") || responseTypes.includes("code")
? await this.buildIdTokenPayload({
user,
client,
sessionHandle: input.session.getHandle(),
scopes,
userContext: input.userContext,
})
: undefined;
const accessToken =
responseTypes.includes("token") || responseTypes.includes("code")
? await this.buildAccessTokenPayload({
user,
client,
sessionHandle: input.session.getHandle(),
scopes,
userContext: input.userContext,
})
: undefined;
payloads = {
idToken,
accessToken,
Expand All @@ -262,7 +274,7 @@ function getRecipeInterface(
const resp = await querier.sendPostRequest(
new normalisedURLPath_1.default(`/recipe/oauth/auth`),
{
params: input.params,
params: Object.assign(Object.assign({}, input.params), { scope: scopes.join(" ") }),
cookies: input.cookies,
session: payloads,
},
Expand Down Expand Up @@ -294,6 +306,8 @@ function getRecipeInterface(
tenantId: input.session.getTenantId(),
rsub: input.session.getRecipeUserId().getAsString(),
sessionHandle: input.session.getHandle(),
initialAccessTokenPayload: payloads === null || payloads === void 0 ? void 0 : payloads.accessToken,
initialIdTokenPayload: payloads === null || payloads === void 0 ? void 0 : payloads.idToken,
});
return {
redirectTo: consentRes.redirectTo,
Expand Down Expand Up @@ -334,24 +348,20 @@ function getRecipeInterface(
};
}
const client = clientInfo.client;
const idToken = await this.buildIdTokenPayload({
body["id_token"] = await this.buildIdTokenPayload({
user: undefined,
client,
sessionHandle: undefined,
scopes,
userContext: input.userContext,
});
const accessTokenPayload = await this.buildAccessTokenPayload({
body["access_token"] = await this.buildAccessTokenPayload({
user: undefined,
client,
sessionHandle: undefined,
scopes,
userContext: input.userContext,
});
body["session"] = {
idToken: idToken,
accessToken: accessTokenPayload,
};
}
if (input.body.grant_type === "refresh_token") {
const scopes =
Expand Down Expand Up @@ -382,24 +392,20 @@ function getRecipeInterface(
if (!user) {
throw new Error("User not found");
}
const idToken = await this.buildIdTokenPayload({
body["id_token"] = await this.buildIdTokenPayload({
user,
client,
sessionHandle,
scopes,
userContext: input.userContext,
});
const accessTokenPayload = await this.buildAccessTokenPayload({
body["access_token"] = await this.buildAccessTokenPayload({
user,
client,
sessionHandle: sessionHandle,
scopes,
userContext: input.userContext,
});
body["session"] = {
idToken: idToken,
accessToken: accessTokenPayload,
};
}
}
if (input.authorizationHeader) {
Expand Down Expand Up @@ -514,6 +520,9 @@ function getRecipeInterface(
};
}
},
getRequestedScopes: async function (input) {
return input.scopeParam;
},
buildAccessTokenPayload: async function (input) {
if (input.user === undefined || input.sessionHandle === undefined) {
return {};
Expand Down Expand Up @@ -617,10 +626,10 @@ function getRecipeInterface(
requestBody.authorizationHeader = input.authorizationHeader;
} else {
if ("clientId" in input && input.clientId !== undefined) {
requestBody.clientId = input.clientId;
requestBody.client_id = input.clientId;
}
if ("clientSecret" in input && input.clientSecret !== undefined) {
requestBody.clientSecret = input.clientSecret;
requestBody.client_secret = input.clientSecret;
}
}
const res = await querier.sendPostRequest(
Expand Down
10 changes: 10 additions & 0 deletions lib/build/recipe/oauth2provider/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { GeneralErrorResponse, JSONObject, JSONValue, NonNullableProperties, Use
import { SessionContainerInterface } from "../session/types";
import { OAuth2Client } from "./OAuth2Client";
import { User } from "../../user";
import RecipeUserId from "../../recipeUserId";
export declare type TypeInput = {
override?: {
functions?: (
Expand Down Expand Up @@ -123,6 +124,8 @@ export declare type RecipeInterface = {
tenantId: string;
rsub: string;
sessionHandle: string;
initialAccessTokenPayload: JSONObject | undefined;
initialIdTokenPayload: JSONObject | undefined;
userContext: UserContext;
}): Promise<{
redirectTo: string;
Expand Down Expand Up @@ -244,6 +247,13 @@ export declare type RecipeInterface = {
status: "OK";
payload: JSONObject;
}>;
getRequestedScopes(input: {
recipeUserId: RecipeUserId | undefined;
sessionHandle: string | undefined;
scopeParam: string[];
clientId: string;
userContext: UserContext;
}): Promise<string[]>;
buildAccessTokenPayload(input: {
user: User | undefined;
client: OAuth2Client;
Expand Down
Loading

0 comments on commit ce33439

Please sign in to comment.