From ed74c7fd17719673b2ae9eb87e42358486041495 Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Thu, 12 Oct 2023 14:27:40 +0200 Subject: [PATCH 1/8] feat: add mfa recipe and info endpoint --- CHANGELOG.md | 6 ++++ api_spec.yaml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4003fa6..b48706b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) +## [1.19.0] - 2023-10-XX + +### Added + +- Added an endpoint to query information about MFA factors + ## [1.18.0] - 2023-08-XX ### Changed diff --git a/api_spec.yaml b/api_spec.yaml index 6a496a3..fdd25e7 100644 --- a/api_spec.yaml +++ b/api_spec.yaml @@ -4,7 +4,7 @@ info: description: | These are the APIs exposed by our backend SDK. To be consumed by the frontend only. `` in all the APIs are optional. Its default value is `public` - version: "1.18.0" + version: "1.19.0" title: Frontend Driver Interface contact: email: team@supertokens.io @@ -16,10 +16,79 @@ tags: - name: Passwordless Recipe - name: ThirdPartyPasswordless Recipe - name: EmailVerification Recipe + - name: MultiFactorAuth Recipe - name: JWT Recipe - name: OpenId Recipe paths: + + /{apiBasePath}/mfa/info: + get: + tags: + - MultiFactorAuth Recipe + operationId: getMFAInfo + description: | + Returns information about the auth factors of the current user and refreshes the related session claim + parameters: + - $ref: '#/components/parameters/apiBasePath' + - $ref: '#/components/parameters/multiFactorAuthRid' + - $ref: '#/components/parameters/anti-csrf' + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + responses: + '200': + description: Information about the auth factors of the current user and optionally the session with a refreshed MFA claim + headers: + Set-Cookie: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + type: string + example: 'sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax' + st-access-token: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + $ref: '#/components/schemas/token' + anti-csrf: + description: Sent if enabled by the user + schema: + $ref: '#/components/schemas/token' + front-token: + description: Sent if the access token payload is updated + schema: + $ref: '#/components/schemas/token' + Access-Control-Expose-Headers: + schema: + type: string + example: 'anti-csrf, front-token, st-access-token' + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: '#/components/schemas/statusOK' + info: + type: object + properties: + isAlreadySetup: + type: array + items: + type: string + isAllowedToSetup: + type: array + items: + type: string + - $ref: '#/components/schemas/generalErrorResponse' + + '404': + $ref: '#/components/responses/404' + + '500': + $ref: '#/components/responses/500' + /{apiBasePath}//signinup/code⠀: post: tags: @@ -2130,6 +2199,13 @@ components: example: multitenancy schema: type: string + + multiFactorAuthRid: + name: rid + in: header + example: multifactorauth + schema: + type: string anti-csrf: name: anti-csrf From 911ddbfa37aa1a3ddb86c7babe58f0bf2e9487e2 Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Fri, 13 Oct 2023 15:17:54 +0200 Subject: [PATCH 2/8] feat: update loginmethods response type to support mfa --- CHANGELOG.md | 1 + api_spec.yaml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b48706b..7e55383 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added an endpoint to query information about MFA factors +- Updated loginmethods response type to include a list of first factors ## [1.18.0] - 2023-08-XX diff --git a/api_spec.yaml b/api_spec.yaml index fdd25e7..5af79df 100644 --- a/api_spec.yaml +++ b/api_spec.yaml @@ -1416,6 +1416,10 @@ paths: enabled: type: boolean example: true + firstFactors: + type: array + items: + type: string - $ref: '#/components/schemas/generalErrorResponse' '404': $ref: '#/components/responses/404' From 8a60daf69703146b47602d48a6c373e7c4160463 Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Fri, 13 Oct 2023 15:19:14 +0200 Subject: [PATCH 3/8] chore: update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e55383..972fdb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added an endpoint to query information about MFA factors -- Updated loginmethods response type to include a list of first factors +- Updated loginmethods (`{apiBasePath}/loginmethods`) response type to include a list of first factors ## [1.18.0] - 2023-08-XX From 4a42214fa665cfffdacb96bf1dca03da32cd95ea Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Mon, 4 Mar 2024 19:03:56 +0100 Subject: [PATCH 4/8] feat: add 403 response to sign in/up apis --- api_spec.yaml | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/api_spec.yaml b/api_spec.yaml index 5af79df..cf4959b 100644 --- a/api_spec.yaml +++ b/api_spec.yaml @@ -146,6 +146,9 @@ paths: example: "Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE)" - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -311,6 +314,9 @@ paths: '404': $ref: '#/components/responses/404' + + '403': + $ref: '#/components/responses/403-factor-setup' '500': $ref: '#/components/responses/500' @@ -473,6 +479,9 @@ paths: - $ref: '#/components/schemas/signinupErrorResponse' - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -623,6 +632,9 @@ paths: example: "Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE)" - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -781,6 +793,9 @@ paths: example: "Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE)" - $ref: '#/components/schemas/generalErrorResponse' + + '403': + $ref: '#/components/responses/403-factor-setup' '404': $ref: '#/components/responses/404' @@ -1019,6 +1034,9 @@ paths: - $ref: '#/components/schemas/wrongCredentialsResponse' - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -1080,6 +1098,9 @@ paths: - $ref: '#/components/schemas/fieldErrorResponse' - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -1283,6 +1304,9 @@ paths: - $ref: '#/components/schemas/signinupErrorResponse' - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -1513,6 +1537,9 @@ paths: - $ref: '#/components/schemas/wrongCredentialsResponse' - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -1574,6 +1601,9 @@ paths: - $ref: '#/components/schemas/fieldErrorResponse' - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -1780,6 +1810,9 @@ paths: - $ref: '#/components/schemas/signinupErrorResponse' - $ref: '#/components/schemas/generalErrorResponse' + '403': + $ref: '#/components/responses/403-factor-setup' + '404': $ref: '#/components/responses/404' @@ -2268,6 +2301,49 @@ components: schema: $ref: "#/components/schemas/notFound" + 403-factor-setup: + description: A claim validation error happened during factor setup + content: + application/json: + schema: + oneOf: + - type: object + properties: + message: + type: string + example: invalid claim + claimValidationErrors: + type: array + items: + type: object + properties: + id: + type: string + example: st-ev + reason: + type: object + example: + message: "wrong value" + expectedValue: true + actualValue: false + - type: object + properties: + message: + type: string + example: invalid claim + claimValidationErrors: + type: array + items: + type: object + properties: + id: + type: string + example: st-mfa + reason: + type: string + example: "Completed factors in the session does not satisfy the MFA requirements for auth" + + schemas: statusOK: type: string From d12fc6c4240176d686fd299e539720de13533a4a Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Fri, 8 Mar 2024 01:10:57 +0100 Subject: [PATCH 5/8] feat: update to match latest FDI --- CHANGELOG.md | 2 +- api_spec.yaml | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 972fdb9..4c3b6e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Added an endpoint to query information about MFA factors +- Added `PUT` `/{apiBasePath}/mfa/info` to query information about MFA factors - Updated loginmethods (`{apiBasePath}/loginmethods`) response type to include a list of first factors ## [1.18.0] - 2023-08-XX diff --git a/api_spec.yaml b/api_spec.yaml index cf4959b..4e0a260 100644 --- a/api_spec.yaml +++ b/api_spec.yaml @@ -23,7 +23,7 @@ paths: /{apiBasePath}/mfa/info: - get: + put: tags: - MultiFactorAuth Recipe operationId: getMFAInfo @@ -70,14 +70,44 @@ paths: properties: status: $ref: '#/components/schemas/statusOK' - info: + factors: + type: object + properties: + alreadySetup: + type: array + items: + type: string + allowedToSetup: + type: array + items: + type: string + next: + type: array + items: + type: string + emails: + type: object + properties: + emailpassword: + type: array + items: + type: string + otp-email: + type: array + items: + type: string + link-email: + type: array + items: + type: string + phoneNumbers: type: object properties: - isAlreadySetup: + otp-phone: type: array items: type: string - isAllowedToSetup: + link-phone: type: array items: type: string @@ -1402,6 +1432,7 @@ paths: - emailPassword - thirdParty - passwordless + - firstFactors properties: emailPassword: type: object From a2afb774b59af7d8c541a7ef3b063555dd8cd08c Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Mon, 11 Mar 2024 01:14:05 +0100 Subject: [PATCH 6/8] feat: add TOTP --- api_spec.yaml | 352 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 351 insertions(+), 1 deletion(-) diff --git a/api_spec.yaml b/api_spec.yaml index 4e0a260..7626cf6 100644 --- a/api_spec.yaml +++ b/api_spec.yaml @@ -17,11 +17,11 @@ tags: - name: ThirdPartyPasswordless Recipe - name: EmailVerification Recipe - name: MultiFactorAuth Recipe + - name: TOTP Recipe - name: JWT Recipe - name: OpenId Recipe paths: - /{apiBasePath}/mfa/info: put: tags: @@ -119,6 +119,349 @@ paths: '500': $ref: '#/components/responses/500' + /{apiBasePath}/totp/device/list: + get: + tags: + - TOTP Recipe + operationId: listTOTPdevices + description: | + List the TOTP devices of the current user + parameters: + - $ref: '#/components/parameters/apiBasePath' + - $ref: '#/components/parameters/totpRid' + - $ref: '#/components/parameters/anti-csrf' + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + responses: + '200': + description: The list of the TOTP devices of the session user + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: '#/components/schemas/statusOK' + devices: + type: array + items: + type: object + properties: + name: + type: string + example: "asdf123" + period: + type: number + example: 30 + skew: + type: number + example: 30 + verified: + type: boolean + example: false + - $ref: '#/components/schemas/generalErrorResponse' + + '404': + $ref: '#/components/responses/404' + + '500': + $ref: '#/components/responses/500' + + /{apiBasePath}/totp/device: + post: + tags: + - TOTP Recipe + operationId: createTOTPDevice + description: | + Creates an unverified totp device + parameters: + - $ref: '#/components/parameters/apiBasePath' + - $ref: '#/components/parameters/totpRid' + - $ref: '#/components/parameters/anti-csrf' + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + requestBody: + content: + application/json: + schema: + type: object + properties: + deviceName: + type: string + example: "asdf123" + responses: + '200': + description: | + Information about the created (unverified) device. Based on the this, + the user can add the device to their TOTP app and verify it. + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: '#/components/schemas/statusOK' + deviceName: + type: string + example: "asfd123" + qrCodeString: + type: string + example: "asfd123" + secret: + type: string + example: "asfd123" + - type: object + properties: + status: + type: string + enum: ['DEVICE_ALREADY_EXISTS_ERROR'] + - $ref: '#/components/schemas/generalErrorResponse' + + '403': + $ref: '#/components/responses/403-factor-setup' + + '404': + $ref: '#/components/responses/404' + + '500': + $ref: '#/components/responses/500' + + /{apiBasePath}/totp/device/remove: + post: + tags: + - TOTP Recipe + operationId: removeTOTPDevice + description: | + Removes a totp device + parameters: + - $ref: '#/components/parameters/apiBasePath' + - $ref: '#/components/parameters/totpRid' + - $ref: '#/components/parameters/anti-csrf' + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + requestBody: + content: + application/json: + schema: + type: object + properties: + deviceName: + type: string + example: "asdf123" + responses: + '200': + description: Success report + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: '#/components/schemas/statusOK' + didDeviceExist: + type: boolean + example: true + - $ref: '#/components/schemas/generalErrorResponse' + + '404': + $ref: '#/components/responses/404' + + '500': + $ref: '#/components/responses/500' + + /{apiBasePath}/totp/device/verify: + post: + tags: + - TOTP Recipe + operationId: verifyTOTPDevice + description: | + Checks that the TOTP sent in the body belongs to the totp device (specified by deviceName, belonging to the session user) + parameters: + - $ref: '#/components/parameters/apiBasePath' + - $ref: '#/components/parameters/totpRid' + - $ref: '#/components/parameters/anti-csrf' + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + requestBody: + content: + application/json: + schema: + type: object + properties: + totp: + type: string + example: "123456" + deviceName: + type: string + example: "asdf123asdf" + + responses: + '200': + description: Verification result and optionally the session with a refreshed MFA claim + headers: + Set-Cookie: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + type: string + example: 'sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax' + st-access-token: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + $ref: '#/components/schemas/token' + anti-csrf: + description: Sent if enabled by the user + schema: + $ref: '#/components/schemas/token' + front-token: + description: Sent if the access token payload is updated + schema: + $ref: '#/components/schemas/token' + Access-Control-Expose-Headers: + schema: + type: string + example: 'anti-csrf, front-token, st-access-token' + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: '#/components/schemas/statusOK' + - type: object + properties: + status: + type: string + enum: ['UNKNOWN_DEVICE_ERROR'] + - type: object + properties: + status: + type: string + enum: ['INVALID_TOTP_ERROR'] + currentNumberOfFailedAttempts: + type: number + example: 2 + maxNumberOfFailedAttempts: + type: number + example: 5 + - type: object + properties: + status: + type: string + enum: ['LIMIT_REACHED_ERROR'] + retryAfterMs: + type: number + example: 30000 + - $ref: '#/components/schemas/generalErrorResponse' + + '403': + $ref: '#/components/responses/403-factor-setup' + + '404': + $ref: '#/components/responses/404' + + '500': + $ref: '#/components/responses/500' + + /{apiBasePath}/totp/verify: + post: + tags: + - TOTP Recipe + operationId: verifyTOTP + description: | + Checks that the TOTP sent in the body belongs to a verified totp device of the session user + parameters: + - $ref: '#/components/parameters/apiBasePath' + - $ref: '#/components/parameters/totpRid' + - $ref: '#/components/parameters/anti-csrf' + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + requestBody: + content: + application/json: + schema: + type: object + properties: + totp: + type: string + example: "123456" + responses: + '200': + description: Verification result and optionally the session with a refreshed MFA claim + headers: + Set-Cookie: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + type: string + example: 'sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax' + st-access-token: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + $ref: '#/components/schemas/token' + anti-csrf: + description: Sent if enabled by the user + schema: + $ref: '#/components/schemas/token' + front-token: + description: Sent if the access token payload is updated + schema: + $ref: '#/components/schemas/token' + Access-Control-Expose-Headers: + schema: + type: string + example: 'anti-csrf, front-token, st-access-token' + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: '#/components/schemas/statusOK' + - type: object + properties: + status: + type: string + enum: ['UNKNOWN_USER_ID_ERROR'] + - type: object + properties: + status: + type: string + enum: ['INVALID_TOTP_ERROR'] + currentNumberOfFailedAttempts: + type: number + example: 2 + maxNumberOfFailedAttempts: + type: number + example: 5 + - type: object + properties: + status: + type: string + enum: ['LIMIT_REACHED_ERROR'] + retryAfterMs: + type: number + example: 30000 + - $ref: '#/components/schemas/generalErrorResponse' + + '404': + $ref: '#/components/responses/404' + + '500': + $ref: '#/components/responses/500' + /{apiBasePath}//signinup/code⠀: post: tags: @@ -2275,6 +2618,13 @@ components: schema: type: string + totpRid: + name: rid + in: header + example: totp + schema: + type: string + anti-csrf: name: anti-csrf in: header From 7a9f515cd4f3af76a1611ebf00f02ef6086d07da Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Mon, 11 Mar 2024 13:55:38 +0100 Subject: [PATCH 7/8] feat: add better qrCodeString example --- api_spec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api_spec.yaml b/api_spec.yaml index 7626cf6..5567b39 100644 --- a/api_spec.yaml +++ b/api_spec.yaml @@ -211,10 +211,10 @@ paths: example: "asfd123" qrCodeString: type: string - example: "asfd123" + example: "otpauth://totp/Supertokens:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Supertokens" secret: type: string - example: "asfd123" + example: "JBSWY3DPEHPK3PXP" - type: object properties: status: From 869911f697bf1b7a352f94673a6f0aac719b5670 Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Mon, 11 Mar 2024 14:01:11 +0100 Subject: [PATCH 8/8] feat: update TOTP interface --- api_spec.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/api_spec.yaml b/api_spec.yaml index 5567b39..3884eb6 100644 --- a/api_spec.yaml +++ b/api_spec.yaml @@ -430,11 +430,6 @@ paths: properties: status: $ref: '#/components/schemas/statusOK' - - type: object - properties: - status: - type: string - enum: ['UNKNOWN_USER_ID_ERROR'] - type: object properties: status: