From a9265c433182e43ea17d453e3d0b5fac981bba6d Mon Sep 17 00:00:00 2001 From: Nemi Shah Date: Wed, 4 Oct 2023 10:11:02 +0530 Subject: [PATCH 1/3] Add explanation for Flutter social login with Apple on ANdroid --- v2/thirdparty/custom-ui/thirdparty-login.mdx | 65 +++++++++++++++++++ .../custom-ui/thirdparty-login.mdx | 65 +++++++++++++++++++ .../custom-ui/thirdparty-login.mdx | 65 +++++++++++++++++++ 3 files changed, 195 insertions(+) diff --git a/v2/thirdparty/custom-ui/thirdparty-login.mdx b/v2/thirdparty/custom-ui/thirdparty-login.mdx index dfe1d6744..4c62e9242 100644 --- a/v2/thirdparty/custom-ui/thirdparty-login.mdx +++ b/v2/thirdparty/custom-ui/thirdparty-login.mdx @@ -373,6 +373,13 @@ void loginWithApple() async { var credential = await SignInWithApple.getAppleIDCredential(scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, + // Required for Android only + webAuthenticationOptions: WebAuthenticationOptions( + clientId: "", + redirectUri: Uri.parse( + "//callback/apple", + ), + ), ]); String authorizationCode = credential.authorizationCode; @@ -387,6 +394,64 @@ void loginWithApple() async { } ``` +In the snippet above for Android we need to pass an additional `webAuthenticationOptions` property when signing in with Apple. This is because on Android the library uses the web login flow and we need to provide it with the client id and redirection uri. The `redirectUri` property here is the URL to which Apple will make a `POST` request after the user has logged in. The SuperTokens backend SDKs provide an API for this at `//callback/apple`. + +

Additional steps for Android

+ +For android we also need to provide a way for the web login flow to redirect back to the app. By default the API provided by the backend SDKs redirect to the website domain you provide when initialising the SDK, we can override the API to have it redirect to our app instead. For example if you were using the Node.js SDK: + +```tsx +import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRecipeName}"; + +^{recipeNameCapitalLetters}.init({ + ^{nodeSignInUpFeatureStart} + // highlight-start + override: { + apis: (original) => { + return { + ...original, + appleRedirectHandlerPOST: async (input) => { + if (original.appleRedirectHandlerPOST === undefined) { + throw Error("Should never come here"); + } + + // inut.formPostInfoFromProvider contains all the query params attached by Apple + const stateInBase64 = input.formPostInfoFromProvider.state; + + // The web SDKs add a default state + if (stateInBase64 === undefined) { + // Redirect to android app + // We create a dummy URL to create the query string + const dummyUrl = new URL("http://localhost:8080"); + for (const [key, value] of Object.entries(input.formPostInfoFromProvider)) { + dummyUrl.searchParams.set(key, `${value}`); + } + + const queryString = dummyUrl.searchParams.toString(); + // Refer to the README of sign_in_with_apple to understand what this url is + const redirectUrl = `intent://callback?${queryString}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end`; + + input.options.res.setHeader("Location", redirectUrl, false); + input.options.res.setStatusCode(303); + input.options.res.sendHTMLResponse(""); + } else { + // For the web flow we can use the original implementation + original.appleRedirectHandlerPOST(input); + } + }, + }; + }, + }, + // highlight-end + providers: [ + // ... + ], + ^{nodeSignInUpFeatureEnd} +}) +``` + +In the code above we override the `appleRedirectHandlerPOST` API to check if the request was made by our Android app (You can skip checking the state if you only have a mobile app and no website). `sign_in_with_apple` requires us to parse the query params sent by apple and include them in the redirect URL in a specific way, and then we simply redirect to the deep link url. Refer to the README for `sign_in_with_apple` to read about the deep link setup required in Android. + diff --git a/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx b/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx index d2ca9d5d1..5e4cb1fc6 100644 --- a/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx +++ b/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx @@ -376,6 +376,13 @@ void loginWithApple() async { var credential = await SignInWithApple.getAppleIDCredential(scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, + // Required for Android only + webAuthenticationOptions: WebAuthenticationOptions( + clientId: "", + redirectUri: Uri.parse( + "//callback/apple", + ), + ), ]); String authorizationCode = credential.authorizationCode; @@ -390,6 +397,64 @@ void loginWithApple() async { } ``` +In the snippet above for Android we need to pass an additional `webAuthenticationOptions` property when signing in with Apple. This is because on Android the library uses the web login flow and we need to provide it with the client id and redirection uri. The `redirectUri` property here is the URL to which Apple will make a `POST` request after the user has logged in. The SuperTokens backend SDKs provide an API for this at `//callback/apple`. + +

Additional steps for Android

+ +For android we also need to provide a way for the web login flow to redirect back to the app. By default the API provided by the backend SDKs redirect to the website domain you provide when initialising the SDK, we can override the API to have it redirect to our app instead. For example if you were using the Node.js SDK: + +```tsx +import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRecipeName}"; + +^{recipeNameCapitalLetters}.init({ + ^{nodeSignInUpFeatureStart} + // highlight-start + override: { + apis: (original) => { + return { + ...original, + appleRedirectHandlerPOST: async (input) => { + if (original.appleRedirectHandlerPOST === undefined) { + throw Error("Should never come here"); + } + + // inut.formPostInfoFromProvider contains all the query params attached by Apple + const stateInBase64 = input.formPostInfoFromProvider.state; + + // The web SDKs add a default state + if (stateInBase64 === undefined) { + // Redirect to android app + // We create a dummy URL to create the query string + const dummyUrl = new URL("http://localhost:8080"); + for (const [key, value] of Object.entries(input.formPostInfoFromProvider)) { + dummyUrl.searchParams.set(key, `${value}`); + } + + const queryString = dummyUrl.searchParams.toString(); + // Refer to the README of sign_in_with_apple to understand what this url is + const redirectUrl = `intent://callback?${queryString}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end`; + + input.options.res.setHeader("Location", redirectUrl, false); + input.options.res.setStatusCode(303); + input.options.res.sendHTMLResponse(""); + } else { + // For the web flow we can use the original implementation + original.appleRedirectHandlerPOST(input); + } + }, + }; + }, + }, + // highlight-end + providers: [ + // ... + ], + ^{nodeSignInUpFeatureEnd} +}) +``` + +In the code above we override the `appleRedirectHandlerPOST` API to check if the request was made by our Android app (You can skip checking the state if you only have a mobile app and no website). `sign_in_with_apple` requires us to parse the query params sent by apple and include them in the redirect URL in a specific way, and then we simply redirect to the deep link url. Refer to the README for `sign_in_with_apple` to read about the deep link setup required in Android. + diff --git a/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx b/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx index fd0ac995c..e3ddfdec0 100644 --- a/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx +++ b/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx @@ -376,6 +376,13 @@ void loginWithApple() async { var credential = await SignInWithApple.getAppleIDCredential(scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, + // Required for Android only + webAuthenticationOptions: WebAuthenticationOptions( + clientId: "", + redirectUri: Uri.parse( + "//callback/apple", + ), + ), ]); String authorizationCode = credential.authorizationCode; @@ -390,6 +397,64 @@ void loginWithApple() async { } ``` +In the snippet above for Android we need to pass an additional `webAuthenticationOptions` property when signing in with Apple. This is because on Android the library uses the web login flow and we need to provide it with the client id and redirection uri. The `redirectUri` property here is the URL to which Apple will make a `POST` request after the user has logged in. The SuperTokens backend SDKs provide an API for this at `//callback/apple`. + +

Additional steps for Android

+ +For android we also need to provide a way for the web login flow to redirect back to the app. By default the API provided by the backend SDKs redirect to the website domain you provide when initialising the SDK, we can override the API to have it redirect to our app instead. For example if you were using the Node.js SDK: + +```tsx +import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRecipeName}"; + +^{recipeNameCapitalLetters}.init({ + ^{nodeSignInUpFeatureStart} + // highlight-start + override: { + apis: (original) => { + return { + ...original, + appleRedirectHandlerPOST: async (input) => { + if (original.appleRedirectHandlerPOST === undefined) { + throw Error("Should never come here"); + } + + // inut.formPostInfoFromProvider contains all the query params attached by Apple + const stateInBase64 = input.formPostInfoFromProvider.state; + + // The web SDKs add a default state + if (stateInBase64 === undefined) { + // Redirect to android app + // We create a dummy URL to create the query string + const dummyUrl = new URL("http://localhost:8080"); + for (const [key, value] of Object.entries(input.formPostInfoFromProvider)) { + dummyUrl.searchParams.set(key, `${value}`); + } + + const queryString = dummyUrl.searchParams.toString(); + // Refer to the README of sign_in_with_apple to understand what this url is + const redirectUrl = `intent://callback?${queryString}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end`; + + input.options.res.setHeader("Location", redirectUrl, false); + input.options.res.setStatusCode(303); + input.options.res.sendHTMLResponse(""); + } else { + // For the web flow we can use the original implementation + original.appleRedirectHandlerPOST(input); + } + }, + }; + }, + }, + // highlight-end + providers: [ + // ... + ], + ^{nodeSignInUpFeatureEnd} +}) +``` + +In the code above we override the `appleRedirectHandlerPOST` API to check if the request was made by our Android app (You can skip checking the state if you only have a mobile app and no website). `sign_in_with_apple` requires us to parse the query params sent by apple and include them in the redirect URL in a specific way, and then we simply redirect to the deep link url. Refer to the README for `sign_in_with_apple` to read about the deep link setup required in Android. + From 6722fb171dfffa4e5912d17ba1a42a63978eb1b4 Mon Sep 17 00:00:00 2001 From: Nemi Shah Date: Wed, 4 Oct 2023 12:22:28 +0530 Subject: [PATCH 2/3] Add golang snippets --- .../custom-ui/email-password-login.mdx | 2 +- v2/thirdparty/custom-ui/thirdparty-login.mdx | 98 +++++++++++++++++-- .../custom-ui/email-password-login.mdx | 2 +- .../custom-ui/thirdparty-login.mdx | 98 +++++++++++++++++-- .../custom-ui/thirdparty-login.mdx | 98 +++++++++++++++++-- 5 files changed, 266 insertions(+), 32 deletions(-) diff --git a/v2/emailpassword/custom-ui/email-password-login.mdx b/v2/emailpassword/custom-ui/email-password-login.mdx index de9928743..5adccfd9f 100644 --- a/v2/emailpassword/custom-ui/email-password-login.mdx +++ b/v2/emailpassword/custom-ui/email-password-login.mdx @@ -261,7 +261,7 @@ curl --location --request GET '^{form_apiDomain}^{form_apiBasePath}/signup/email The response body from the API call has a `status` property in it: -- `status: "OK"`: The response will also contain a `doesExist` boolean which will be `true` if the input email already belongs to an email password user. +- `status: "OK"`: The response will also contain a `exists` boolean which will be `true` if the input email already belongs to an email password user. - `status: "GENERAL_ERROR"`: This is only possible if you have overriden the backend API to send back a custom error message which should be displayed on the frontend. diff --git a/v2/thirdparty/custom-ui/thirdparty-login.mdx b/v2/thirdparty/custom-ui/thirdparty-login.mdx index 4c62e9242..c1efaf657 100644 --- a/v2/thirdparty/custom-ui/thirdparty-login.mdx +++ b/v2/thirdparty/custom-ui/thirdparty-login.mdx @@ -323,6 +323,8 @@ Coming Soon +

Step 1) Fetching the authorisation token on the frontend

+ For iOS you use the normal sign in with apple flow and then use the id token to login with SuperTokens ```swift @@ -363,6 +365,8 @@ fileprivate class ViewController: UIViewController, ASAuthorizationControllerPre +

Step 1) Fetching the authorisation token on the frontend

+ For flutter we use the [sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) package, make sure to follow the prerequisites steps to get the package setup. After setup use the snippet below to trigger the apple sign in flow. ```dart @@ -370,19 +374,22 @@ import 'package:sign_in_with_apple/sign_in_with_apple.dart'; void loginWithApple() async { try { - var credential = await SignInWithApple.getAppleIDCredential(scopes: [ - AppleIDAuthorizationScopes.email, - AppleIDAuthorizationScopes.fullName, - // Required for Android only - webAuthenticationOptions: WebAuthenticationOptions( - clientId: "", - redirectUri: Uri.parse( - "//callback/apple", + var credential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + // Required for Android only + webAuthenticationOptions: WebAuthenticationOptions( + clientId: "", + redirectUri: Uri.parse( + "//callback/apple", + ), ), - ), - ]); + ); String authorizationCode = credential.authorizationCode; + String? idToken = credential.identityToken; String? email = credential.email; String? firstname = credential.givenName; String? lastName = credential.familyName; @@ -400,6 +407,10 @@ In the snippet above for Android we need to pass an additional `webAuthenticatio For android we also need to provide a way for the web login flow to redirect back to the app. By default the API provided by the backend SDKs redirect to the website domain you provide when initialising the SDK, we can override the API to have it redirect to our app instead. For example if you were using the Node.js SDK: + + + + ```tsx import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRecipeName}"; @@ -450,6 +461,73 @@ import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRec }) ``` + + + + +```go +import ( + "net/http" + "strings" + + "github.com/supertokens/supertokens-golang/recipe/^{codeImportRecipeName}" + ^{goTPModelsImport} + "github.com/supertokens/supertokens-golang/recipe/^{codeImportRecipeName}/^{goModelName}" +) + +func main() { + ^{codeImportRecipeName}.Init(^{goModelNameForInit}.TypeInput{ + Override: &^{goModelName}.OverrideStruct{ + APIs: func(originalImplementation ^{goModelName}.APIInterface) ^{goModelName}.APIInterface { + originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST + + *originalImplementation.AppleRedirectHandlerPOST = func(formPostInfoFromProvider map[string]interface{}, options tpmodels.APIOptions, userContext *map[string]interface{}) error { + // formPostInfoFromProvider contains all the query params attached by Apple + state, stateOk := formPostInfoFromProvider["state"].(string) + + queryParams := []string{} + if (!stateOk) || state == "" { + // Redirect to android app + for key, value := range formPostInfoFromProvider { + queryParams = append(queryParams, key+"="+value.(string)) + } + + queryString := "" + if len(queryParams) > 0 { + queryString = strings.Join(queryParams, "&") + } + + // Refer to the README of sign_in_with_apple to understand what this url is + redirectUri := "intent://callback?" + queryString + "#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" + + options.Res.Header().Set("Location", redirectUri) + options.Res.WriteHeader(http.StatusSeeOther) + return nil + } else { + return originalAppleRedirectPost(formPostInfoFromProvider, options, userContext) + } + } + + return originalImplementation + }, + }, + ^{goSignInUpFeatureStart} + Providers: []tpmodels.ProviderInput{ + // ... + }, + ^{goSignInUpFeatureEnd} + }) +} +``` + + + + + + + + + In the code above we override the `appleRedirectHandlerPOST` API to check if the request was made by our Android app (You can skip checking the state if you only have a mobile app and no website). `sign_in_with_apple` requires us to parse the query params sent by apple and include them in the redirect URL in a specific way, and then we simply redirect to the deep link url. Refer to the README for `sign_in_with_apple` to read about the deep link setup required in Android.
diff --git a/v2/thirdpartyemailpassword/custom-ui/email-password-login.mdx b/v2/thirdpartyemailpassword/custom-ui/email-password-login.mdx index 6fdc91f11..2d70f8be3 100644 --- a/v2/thirdpartyemailpassword/custom-ui/email-password-login.mdx +++ b/v2/thirdpartyemailpassword/custom-ui/email-password-login.mdx @@ -264,7 +264,7 @@ curl --location --request GET '^{form_apiDomain}^{form_apiBasePath}/signup/email The response body from the API call has a `status` property in it: -- `status: "OK"`: The response will also contain a `doesExist` boolean which will be `true` if the input email already belongs to an email password user. +- `status: "OK"`: The response will also contain a `exists` boolean which will be `true` if the input email already belongs to an email password user. - `status: "GENERAL_ERROR"`: This is only possible if you have overriden the backend API to send back a custom error message which should be displayed on the frontend.
diff --git a/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx b/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx index 5e4cb1fc6..485ffe435 100644 --- a/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx +++ b/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx @@ -326,6 +326,8 @@ Coming Soon +

Step 1) Fetching the authorisation token on the frontend

+ For iOS you use the normal sign in with apple flow and then use the id token to login with SuperTokens ```swift @@ -366,6 +368,8 @@ fileprivate class ViewController: UIViewController, ASAuthorizationControllerPre +

Step 1) Fetching the authorisation token on the frontend

+ For flutter we use the [sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) package, make sure to follow the prerequisites steps to get the package setup. After setup use the snippet below to trigger the apple sign in flow. ```dart @@ -373,19 +377,22 @@ import 'package:sign_in_with_apple/sign_in_with_apple.dart'; void loginWithApple() async { try { - var credential = await SignInWithApple.getAppleIDCredential(scopes: [ - AppleIDAuthorizationScopes.email, - AppleIDAuthorizationScopes.fullName, - // Required for Android only - webAuthenticationOptions: WebAuthenticationOptions( - clientId: "", - redirectUri: Uri.parse( - "//callback/apple", + var credential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + // Required for Android only + webAuthenticationOptions: WebAuthenticationOptions( + clientId: "", + redirectUri: Uri.parse( + "//callback/apple", + ), ), - ), - ]); + ); String authorizationCode = credential.authorizationCode; + String? idToken = credential.identityToken; String? email = credential.email; String? firstname = credential.givenName; String? lastName = credential.familyName; @@ -403,6 +410,10 @@ In the snippet above for Android we need to pass an additional `webAuthenticatio For android we also need to provide a way for the web login flow to redirect back to the app. By default the API provided by the backend SDKs redirect to the website domain you provide when initialising the SDK, we can override the API to have it redirect to our app instead. For example if you were using the Node.js SDK: + + + + ```tsx import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRecipeName}"; @@ -453,6 +464,73 @@ import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRec }) ``` + + + + +```go +import ( + "net/http" + "strings" + + "github.com/supertokens/supertokens-golang/recipe/^{codeImportRecipeName}" + ^{goTPModelsImport} + "github.com/supertokens/supertokens-golang/recipe/^{codeImportRecipeName}/^{goModelName}" +) + +func main() { + ^{codeImportRecipeName}.Init(^{goModelNameForInit}.TypeInput{ + Override: &^{goModelName}.OverrideStruct{ + APIs: func(originalImplementation ^{goModelName}.APIInterface) ^{goModelName}.APIInterface { + originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST + + *originalImplementation.AppleRedirectHandlerPOST = func(formPostInfoFromProvider map[string]interface{}, options tpmodels.APIOptions, userContext *map[string]interface{}) error { + // formPostInfoFromProvider contains all the query params attached by Apple + state, stateOk := formPostInfoFromProvider["state"].(string) + + queryParams := []string{} + if (!stateOk) || state == "" { + // Redirect to android app + for key, value := range formPostInfoFromProvider { + queryParams = append(queryParams, key+"="+value.(string)) + } + + queryString := "" + if len(queryParams) > 0 { + queryString = strings.Join(queryParams, "&") + } + + // Refer to the README of sign_in_with_apple to understand what this url is + redirectUri := "intent://callback?" + queryString + "#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" + + options.Res.Header().Set("Location", redirectUri) + options.Res.WriteHeader(http.StatusSeeOther) + return nil + } else { + return originalAppleRedirectPost(formPostInfoFromProvider, options, userContext) + } + } + + return originalImplementation + }, + }, + ^{goSignInUpFeatureStart} + Providers: []tpmodels.ProviderInput{ + // ... + }, + ^{goSignInUpFeatureEnd} + }) +} +``` + + + + + + + + + In the code above we override the `appleRedirectHandlerPOST` API to check if the request was made by our Android app (You can skip checking the state if you only have a mobile app and no website). `sign_in_with_apple` requires us to parse the query params sent by apple and include them in the redirect URL in a specific way, and then we simply redirect to the deep link url. Refer to the README for `sign_in_with_apple` to read about the deep link setup required in Android.
diff --git a/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx b/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx index e3ddfdec0..2484d2e1d 100644 --- a/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx +++ b/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx @@ -326,6 +326,8 @@ Coming Soon +

Step 1) Fetching the authorisation token on the frontend

+ For iOS you use the normal sign in with apple flow and then use the id token to login with SuperTokens ```swift @@ -366,6 +368,8 @@ fileprivate class ViewController: UIViewController, ASAuthorizationControllerPre +

Step 1) Fetching the authorisation token on the frontend

+ For flutter we use the [sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) package, make sure to follow the prerequisites steps to get the package setup. After setup use the snippet below to trigger the apple sign in flow. ```dart @@ -373,19 +377,22 @@ import 'package:sign_in_with_apple/sign_in_with_apple.dart'; void loginWithApple() async { try { - var credential = await SignInWithApple.getAppleIDCredential(scopes: [ - AppleIDAuthorizationScopes.email, - AppleIDAuthorizationScopes.fullName, - // Required for Android only - webAuthenticationOptions: WebAuthenticationOptions( - clientId: "", - redirectUri: Uri.parse( - "//callback/apple", + var credential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + // Required for Android only + webAuthenticationOptions: WebAuthenticationOptions( + clientId: "", + redirectUri: Uri.parse( + "//callback/apple", + ), ), - ), - ]); + ); String authorizationCode = credential.authorizationCode; + String? idToken = credential.identityToken; String? email = credential.email; String? firstname = credential.givenName; String? lastName = credential.familyName; @@ -403,6 +410,10 @@ In the snippet above for Android we need to pass an additional `webAuthenticatio For android we also need to provide a way for the web login flow to redirect back to the app. By default the API provided by the backend SDKs redirect to the website domain you provide when initialising the SDK, we can override the API to have it redirect to our app instead. For example if you were using the Node.js SDK: + + + + ```tsx import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRecipeName}"; @@ -453,6 +464,73 @@ import ^{recipeNameCapitalLetters} from "supertokens-node/recipe/^{codeImportRec }) ``` + + + + +```go +import ( + "net/http" + "strings" + + "github.com/supertokens/supertokens-golang/recipe/^{codeImportRecipeName}" + ^{goTPModelsImport} + "github.com/supertokens/supertokens-golang/recipe/^{codeImportRecipeName}/^{goModelName}" +) + +func main() { + ^{codeImportRecipeName}.Init(^{goModelNameForInit}.TypeInput{ + Override: &^{goModelName}.OverrideStruct{ + APIs: func(originalImplementation ^{goModelName}.APIInterface) ^{goModelName}.APIInterface { + originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST + + *originalImplementation.AppleRedirectHandlerPOST = func(formPostInfoFromProvider map[string]interface{}, options tpmodels.APIOptions, userContext *map[string]interface{}) error { + // formPostInfoFromProvider contains all the query params attached by Apple + state, stateOk := formPostInfoFromProvider["state"].(string) + + queryParams := []string{} + if (!stateOk) || state == "" { + // Redirect to android app + for key, value := range formPostInfoFromProvider { + queryParams = append(queryParams, key+"="+value.(string)) + } + + queryString := "" + if len(queryParams) > 0 { + queryString = strings.Join(queryParams, "&") + } + + // Refer to the README of sign_in_with_apple to understand what this url is + redirectUri := "intent://callback?" + queryString + "#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" + + options.Res.Header().Set("Location", redirectUri) + options.Res.WriteHeader(http.StatusSeeOther) + return nil + } else { + return originalAppleRedirectPost(formPostInfoFromProvider, options, userContext) + } + } + + return originalImplementation + }, + }, + ^{goSignInUpFeatureStart} + Providers: []tpmodels.ProviderInput{ + // ... + }, + ^{goSignInUpFeatureEnd} + }) +} +``` + + + + + + + + + In the code above we override the `appleRedirectHandlerPOST` API to check if the request was made by our Android app (You can skip checking the state if you only have a mobile app and no website). `sign_in_with_apple` requires us to parse the query params sent by apple and include them in the redirect URL in a specific way, and then we simply redirect to the deep link url. Refer to the README for `sign_in_with_apple` to read about the deep link setup required in Android.
From 2f4f9486b4af8c7c040ee3f3e07f9d5253eadf51 Mon Sep 17 00:00:00 2001 From: Nemi Shah Date: Wed, 4 Oct 2023 12:44:01 +0530 Subject: [PATCH 3/3] Add python code --- v2/thirdparty/custom-ui/thirdparty-login.mdx | 56 +++++++++++++++++++ .../custom-ui/thirdparty-login.mdx | 56 +++++++++++++++++++ .../custom-ui/thirdparty-login.mdx | 56 +++++++++++++++++++ 3 files changed, 168 insertions(+) diff --git a/v2/thirdparty/custom-ui/thirdparty-login.mdx b/v2/thirdparty/custom-ui/thirdparty-login.mdx index c1efaf657..696acc7f0 100644 --- a/v2/thirdparty/custom-ui/thirdparty-login.mdx +++ b/v2/thirdparty/custom-ui/thirdparty-login.mdx @@ -478,6 +478,7 @@ import ( func main() { ^{codeImportRecipeName}.Init(^{goModelNameForInit}.TypeInput{ Override: &^{goModelName}.OverrideStruct{ + // highlight-start APIs: func(originalImplementation ^{goModelName}.APIInterface) ^{goModelName}.APIInterface { originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST @@ -511,6 +512,7 @@ func main() { return originalImplementation }, }, + // highlight-end ^{goSignInUpFeatureStart} Providers: []tpmodels.ProviderInput{ // ... @@ -524,6 +526,60 @@ func main() { +```python +from supertokens_python.recipe import ^{codeImportRecipeName} +from supertokens_python.recipe.^{codeImportRecipeName}.interfaces import APIInterface, APIOptions +from typing import Union, Dict, Any +from supertokens_python.recipe.thirdparty.provider import Provider, RedirectUriInfo + +# highlight-start +def override_thirdparty_apis(original_implementation: APIInterface): + original_apple_redirect_post = original_implementation.apple_redirect_handler_post + + async def apple_redirect_handler_post( + form_post_info: Dict[str, Any], + api_options: APIOptions, + user_context: Dict[str, Any] + ): + # form_post_info contains all the query params attached by Apple + state = form_post_info["state"] + + # The web SDKs add a default state + if state is None: + query_items = [] + + for key, value in form_post_info.items(): + query_items.append(f"{key}={value}") + + query_string = "&".join(query_items) + + # Refer to the README of sign_in_with_apple to understand what this url is + redirect_url = f"intent://callback?${query_string}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" + + api_options.response.set_header("Location", redirect_url) + api_options.response.set_status_code(303) + api_options.response.set_html_content("") + else: + return original_apple_redirect_post(form_post_info, api_options, user_context) + + original_implementation.apple_redirect_handler_post = apple_redirect_handler_post + return original_implementation +# highlight-end + +^{codeImportRecipeName}.init( + # highlight-start + override=^{codeImportRecipeName}.InputOverrideConfig( + apis=override_thirdparty_apis + ), + # highlight-end + ^{pythonSignInUpFeatureStart} + providers=[ + # ... + ] + ^{pythonSignInUpFeatureEnd} +) +``` + diff --git a/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx b/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx index 485ffe435..288aa0409 100644 --- a/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx +++ b/v2/thirdpartyemailpassword/custom-ui/thirdparty-login.mdx @@ -481,6 +481,7 @@ import ( func main() { ^{codeImportRecipeName}.Init(^{goModelNameForInit}.TypeInput{ Override: &^{goModelName}.OverrideStruct{ + // highlight-start APIs: func(originalImplementation ^{goModelName}.APIInterface) ^{goModelName}.APIInterface { originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST @@ -514,6 +515,7 @@ func main() { return originalImplementation }, }, + // highlight-end ^{goSignInUpFeatureStart} Providers: []tpmodels.ProviderInput{ // ... @@ -527,6 +529,60 @@ func main() { +```python +from supertokens_python.recipe import ^{codeImportRecipeName} +from supertokens_python.recipe.^{codeImportRecipeName}.interfaces import APIInterface, APIOptions +from typing import Union, Dict, Any +from supertokens_python.recipe.thirdparty.provider import Provider, RedirectUriInfo + +# highlight-start +def override_thirdparty_apis(original_implementation: APIInterface): + original_apple_redirect_post = original_implementation.apple_redirect_handler_post + + async def apple_redirect_handler_post( + form_post_info: Dict[str, Any], + api_options: APIOptions, + user_context: Dict[str, Any] + ): + # form_post_info contains all the query params attached by Apple + state = form_post_info["state"] + + # The web SDKs add a default state + if state is None: + query_items = [] + + for key, value in form_post_info.items(): + query_items.append(f"{key}={value}") + + query_string = "&".join(query_items) + + # Refer to the README of sign_in_with_apple to understand what this url is + redirect_url = f"intent://callback?${query_string}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" + + api_options.response.set_header("Location", redirect_url) + api_options.response.set_status_code(303) + api_options.response.set_html_content("") + else: + return original_apple_redirect_post(form_post_info, api_options, user_context) + + original_implementation.apple_redirect_handler_post = apple_redirect_handler_post + return original_implementation +# highlight-end + +^{codeImportRecipeName}.init( + # highlight-start + override=^{codeImportRecipeName}.InputOverrideConfig( + apis=override_thirdparty_apis + ), + # highlight-end + ^{pythonSignInUpFeatureStart} + providers=[ + # ... + ] + ^{pythonSignInUpFeatureEnd} +) +``` + diff --git a/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx b/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx index 2484d2e1d..b6534a7a3 100644 --- a/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx +++ b/v2/thirdpartypasswordless/custom-ui/thirdparty-login.mdx @@ -481,6 +481,7 @@ import ( func main() { ^{codeImportRecipeName}.Init(^{goModelNameForInit}.TypeInput{ Override: &^{goModelName}.OverrideStruct{ + // highlight-start APIs: func(originalImplementation ^{goModelName}.APIInterface) ^{goModelName}.APIInterface { originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST @@ -514,6 +515,7 @@ func main() { return originalImplementation }, }, + // highlight-end ^{goSignInUpFeatureStart} Providers: []tpmodels.ProviderInput{ // ... @@ -527,6 +529,60 @@ func main() { +```python +from supertokens_python.recipe import ^{codeImportRecipeName} +from supertokens_python.recipe.^{codeImportRecipeName}.interfaces import APIInterface, APIOptions +from typing import Union, Dict, Any +from supertokens_python.recipe.thirdparty.provider import Provider, RedirectUriInfo + +# highlight-start +def override_thirdparty_apis(original_implementation: APIInterface): + original_apple_redirect_post = original_implementation.apple_redirect_handler_post + + async def apple_redirect_handler_post( + form_post_info: Dict[str, Any], + api_options: APIOptions, + user_context: Dict[str, Any] + ): + # form_post_info contains all the query params attached by Apple + state = form_post_info["state"] + + # The web SDKs add a default state + if state is None: + query_items = [] + + for key, value in form_post_info.items(): + query_items.append(f"{key}={value}") + + query_string = "&".join(query_items) + + # Refer to the README of sign_in_with_apple to understand what this url is + redirect_url = f"intent://callback?${query_string}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" + + api_options.response.set_header("Location", redirect_url) + api_options.response.set_status_code(303) + api_options.response.set_html_content("") + else: + return original_apple_redirect_post(form_post_info, api_options, user_context) + + original_implementation.apple_redirect_handler_post = apple_redirect_handler_post + return original_implementation +# highlight-end + +^{codeImportRecipeName}.init( + # highlight-start + override=^{codeImportRecipeName}.InputOverrideConfig( + apis=override_thirdparty_apis + ), + # highlight-end + ^{pythonSignInUpFeatureStart} + providers=[ + # ... + ] + ^{pythonSignInUpFeatureEnd} +) +``` +