diff --git a/packages/connect-react/src/components/login/LoginInitScreen.tsx b/packages/connect-react/src/components/login/LoginInitScreen.tsx index e3985663f..b7efcbe7d 100644 --- a/packages/connect-react/src/components/login/LoginInitScreen.tsx +++ b/packages/connect-react/src/components/login/LoginInitScreen.tsx @@ -151,6 +151,7 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { () => { return; }, + loadedMs, ); if (res.err) { diff --git a/packages/web-core/openapi/spec_v2.yaml b/packages/web-core/openapi/spec_v2.yaml index 3f783716c..f8914cba9 100644 --- a/packages/web-core/openapi/spec_v2.yaml +++ b/packages/web-core/openapi/spec_v2.yaml @@ -1137,6 +1137,8 @@ components: type: boolean shortSessionCookieConfig: $ref: '#/components/schemas/shortSessionCookieConfig' + sessionTokenCookieConfig: + $ref: '#/components/schemas/sessionTokenCookieConfig' frontendApiUrl: type: string @@ -1170,9 +1172,13 @@ components: type: object required: - shortSession + - sessionToken properties: shortSession: type: string + deprecated: true + sessionToken: + type: string mePasskeyDeleteRsp: type: object @@ -1266,6 +1272,9 @@ components: type: boolean assertionResponse: type: string + loadedMs: + type: integer + format: int64 connectLoginFinishRsp: type: object @@ -1592,6 +1601,28 @@ components: type: boolean shortSessionCookieConfig: + type: object + deprecated: true + required: + - domain + - secure + - sameSite + - path + - lifetimeSeconds + properties: + domain: + type: string + secure: + type: boolean + sameSite: + type: string + enum: [ 'lax', 'strict', 'none' ] + path: + type: string + lifetimeSeconds: + type: integer + + sessionTokenCookieConfig: type: object required: - domain @@ -1820,14 +1851,22 @@ components: required: - blockType - shortSession + - sessionToken properties: blockType: type: string longSession: type: string - description: Only given when project environment is dev + deprecated: true + description: This is only set if the project environment is set to 'dev'. If set the UI components will set the longSession in local storage because the cookie dropping will not work in Safari for example ("third-party cookie"). + refreshToken: + type: string + description: This is only set if the project environment is set to 'dev'. If set the UI components will set the longSession in local storage because the cookie dropping will not work in Safari for example ("third-party cookie"). shortSession: type: string + deprecated: true + sessionToken: + type: string passkeyOperation: $ref: '#/components/schemas/passkeyOperation' diff --git a/packages/web-core/src/api/v2/api.ts b/packages/web-core/src/api/v2/api.ts index adab9da74..5ac2a472e 100644 --- a/packages/web-core/src/api/v2/api.ts +++ b/packages/web-core/src/api/v2/api.ts @@ -445,6 +445,12 @@ export interface ConnectLoginFinishReq { * @memberof ConnectLoginFinishReq */ 'assertionResponse': string; + /** + * + * @type {number} + * @memberof ConnectLoginFinishReq + */ + 'loadedMs'?: number; } /** * @@ -855,17 +861,31 @@ export interface GeneralBlockCompleted { */ 'blockType': string; /** - * Only given when project environment is dev + * This is only set if the project environment is set to \'dev\'. If set the UI components will set the longSession in local storage because the cookie dropping will not work in Safari for example (\"third-party cookie\"). * @type {string} * @memberof GeneralBlockCompleted + * @deprecated */ 'longSession'?: string; + /** + * This is only set if the project environment is set to \'dev\'. If set the UI components will set the longSession in local storage because the cookie dropping will not work in Safari for example (\"third-party cookie\"). + * @type {string} + * @memberof GeneralBlockCompleted + */ + 'refreshToken'?: string; /** * * @type {string} * @memberof GeneralBlockCompleted + * @deprecated */ 'shortSession': string; + /** + * + * @type {string} + * @memberof GeneralBlockCompleted + */ + 'sessionToken': string; /** * * @type {PasskeyOperation} @@ -1644,8 +1664,15 @@ export interface MeRefreshRsp { * * @type {string} * @memberof MeRefreshRsp + * @deprecated */ 'shortSession': string; + /** + * + * @type {string} + * @memberof MeRefreshRsp + */ + 'sessionToken': string; } /** * @@ -2163,8 +2190,15 @@ export interface SessionConfigRsp { * * @type {ShortSessionCookieConfig} * @memberof SessionConfigRsp + * @deprecated */ 'shortSessionCookieConfig'?: ShortSessionCookieConfig; + /** + * + * @type {SessionTokenCookieConfig} + * @memberof SessionConfigRsp + */ + 'sessionTokenCookieConfig'?: SessionTokenCookieConfig; /** * * @type {string} @@ -2172,6 +2206,52 @@ export interface SessionConfigRsp { */ 'frontendApiUrl'?: string; } +/** + * + * @export + * @interface SessionTokenCookieConfig + */ +export interface SessionTokenCookieConfig { + /** + * + * @type {string} + * @memberof SessionTokenCookieConfig + */ + 'domain': string; + /** + * + * @type {boolean} + * @memberof SessionTokenCookieConfig + */ + 'secure': boolean; + /** + * + * @type {string} + * @memberof SessionTokenCookieConfig + */ + 'sameSite': SessionTokenCookieConfigSameSiteEnum; + /** + * + * @type {string} + * @memberof SessionTokenCookieConfig + */ + 'path': string; + /** + * + * @type {number} + * @memberof SessionTokenCookieConfig + */ + 'lifetimeSeconds': number; +} + +export const SessionTokenCookieConfigSameSiteEnum = { + Lax: 'lax', + Strict: 'strict', + None: 'none' +} as const; + +export type SessionTokenCookieConfigSameSiteEnum = typeof SessionTokenCookieConfigSameSiteEnum[keyof typeof SessionTokenCookieConfigSameSiteEnum]; + /** * * @export diff --git a/packages/web-core/src/services/ConnectService.ts b/packages/web-core/src/services/ConnectService.ts index 80ddaea90..bff8163ab 100644 --- a/packages/web-core/src/services/ConnectService.ts +++ b/packages/web-core/src/services/ConnectService.ts @@ -225,8 +225,8 @@ export class ConnectService { connectToken?: string, ac?: AbortController, ): Promise> { - const existingProcess = await this.#getExistingProcess(() => this.loginInit(ac ?? new AbortController())); - if (!existingProcess) { + const existingProcess = await this.loginInit(ac ?? new AbortController()); + if (existingProcess.err) { return Err(CorbadoError.missingInit()); } @@ -279,6 +279,7 @@ export class ConnectService { preWebAuthn: (ac: AbortController) => void, postWebAuthn: () => void, onLoginEnd: () => void, + loadedMs: number, ): Promise> { const existingProcess = await this.#getExistingProcess(() => this.loginInit(new AbortController())); if (!existingProcess) { @@ -297,7 +298,7 @@ export class ConnectService { } postWebAuthn(); - const loginFinishResp = await this.#loginFinish(res.val, true); + const loginFinishResp = await this.#loginFinish(res.val, true, loadedMs); onLoginEnd(); return loginFinishResp; @@ -432,6 +433,7 @@ export class ConnectService { async #loginFinish( assertionResponse: string, isConditionalUI: boolean, + loadedMs?: number, ): Promise> { const existingProcess = await this.#getExistingProcess(() => this.loginInit(new AbortController())); if (!existingProcess) { @@ -439,7 +441,7 @@ export class ConnectService { } const res = await this.wrapWithErr(() => - this.#connectApi.connectLoginFinish({ assertionResponse, isConditionalUI }, { timeout: 15 * 1000 }), + this.#connectApi.connectLoginFinish({ assertionResponse, isConditionalUI, loadedMs }, { timeout: 15 * 1000 }), ); if (isConditionalUI) {