{"_id":"@amischencko/capacitor-oauth2","_rev":"2-d05b200cd6a7900b12a44244248c59f9","name":"@amischencko/capacitor-oauth2","dist-tags":{"latest":"3.0.0"},"versions":{"2.1.0":{"name":"@amischencko/capacitor-oauth2","version":"2.1.0","description":"Simple Capacitor OAuth 2 client plugin","author":{"name":"Michael Oberwasserlechner"},"homepage":"https://github.com/amischenko/capacitor-oauth2","license":"MIT","main":"dist/esm/index.js","types":"dist/esm/index.d.ts","scripts":{"build":"npm run clean && tsc","clean":"rm -rf ./dist","watch":"tsc --watch","test":"jest","removePacked":"rm -f byteowls-capacitor-oauth2-*.tgz","publishLocally":"npm run removePacked && npm run build && npm pack","prepublishOnly":"npm run build"},"keywords":["capacitor","capacitor-plugin","oauth2","oauth2-client","social-login"],"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"type":"git","url":"git+https://github.com/amischenko/capacitor-oauth2.git"},"bugs":{"url":"https://github.com/amischenko/capacitor-oauth2/issues"},"publishConfig":{"access":"public"},"peerDependencies":{"@capacitor/core":"^2.0.0"},"dependencies":{},"devDependencies":{"@capacitor/android":"2.4.0","@capacitor/core":"2.4.0","@capacitor/ios":"2.4.0","@types/jest":"26.0.10","jest":"26.4.2","ts-jest":"26.3.0","typescript":"3.8.3"},"gitHead":"c77ce3ba3f9e2402d27954e69c34f8f7d38d1017","_id":"@amischencko/capacitor-oauth2@2.1.0","_nodeVersion":"12.13.0","_npmVersion":"6.11.2","dist":{"integrity":"sha512-+TsIgbGfmk29WjDEPCpLDz1ZYz3MJGLd30CM6iGJzE2x6kvhPYQzL5gl2bvZeHWXQxBVQHkFvOdmjfyC16g2aw==","shasum":"fe22eac276e042027ca2e3f3cefa1904f11112ce","tarball":"https://registry.npmjs.org/@amischencko/capacitor-oauth2/-/capacitor-oauth2-2.1.0.tgz","fileCount":49,"unpackedSize":222083,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwYF4CRA9TVsSAnZWagAAnrEP/jJmTqk5eUJzwdk+LBNX\nNUPXOE+OEYp3vIrx+DEH6RMjgo4VdcN83xv4lUn51J3SWa2mhOaqMepaLXie\nSEJM8EtgXcHG5kRGnGuR5lKPJkfLToHiTu0XS9r5A6Xoir18hyg9sCaOfx9a\nP/r53J33neaFOkiTPD9RSMDdVAZv4CTRMCarHszrbo7NWA/EWyK98vm/J4gX\nAUeEZMio4Du4TKYmJyS+6hwMBOazo2/107IM/uhYqfhHt6aZOJVO4rS8dVki\nsDjMqJfqL0ezYlAkL1O96At6rTa6b/j/tPj5S7AXw7iHN6h6b4Mw/+2SGV1M\neFKs1/Gdk+HTJj6FXWI7MXIoZmCXeTNZwmIMJWVBJ8t2JAKoRhoD0nlJy6nB\nOXFUb/J9eIr7ynH5+5pt2z5kqk25UwZBo4YAxhFeE3RW+MUlQez1NBJ+vekI\n5gyPTwnu4TdNzZMi9nLbUUIP/4jw7TEaIOHzMn5JnMRDM8OiDWi+g4qbxTqf\nM+nNpmptgIEHp+/NdDrqsff/8cta9hO1XmHBtAtq7ug4y99x9/dYI2N/e2ir\n2WArsLkg3W6udQAnsJXY4kFhX6oAa0c1EJNAmTOE51fZnm1V/c7OhyiM51PB\nh1pxVyar8JCGlPqcVOyWK1UKpJ+dLUQM3XStXaOldks7cPB80kpZ+/KlGOKy\nl26N\r\n=31tE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEeG8HrqMFmbR19NBuy7u2EThCZRpCf6EbJXunrVwfdjAiEAkVDLrNMELELr1iDaB95OvBFlSdK3JCpIvrVEeOHBAtM="}]},"_npmUser":{"name":"amischenko","email":"a.mischencko@gmail.com"},"directories":{},"maintainers":[{"name":"amischenko","email":"a.mischencko@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/capacitor-oauth2_2.1.0_1623294328666_0.5302745254564154"},"_hasShrinkwrap":false},"3.0.0":{"name":"@amischencko/capacitor-oauth2","version":"3.0.0","description":"Capacitor OAuth 2 client plugin","author":{"name":"Michael Oberwasserlechner"},"homepage":"https://github.com/amischenko/capacitor-oauth2","license":"MIT","main":"dist/esm/index.js","module":"dist/esm/index.js","types":"dist/esm/index.d.ts","scripts":{"build":"npm run clean && tsc","clean":"rm -rf ./dist","watch":"tsc --watch","test":"jest","removePacked":"rm -f capacitor-oauth2-*.tgz","publishLocally":"npm run removePacked && npm run build && npm pack","prepublishOnly":"npm run build"},"keywords":["capacitor","capacitor-plugin","oauth2","oauth2-client","social-login"],"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"type":"git","url":"git+https://github.com/amischenko/capacitor-oauth2.git"},"bugs":{"url":"https://github.com/amischenko/capacitor-oauth2/issues"},"publishConfig":{"access":"public"},"peerDependencies":{"@capacitor/core":"^3.0.0"},"dependencies":{},"devDependencies":{"@capacitor/android":"3.0.2","@capacitor/core":"3.0.2","@capacitor/ios":"3.0.2","@types/jest":"26.0.23","jest":"27.0.6","ts-jest":"27.0.3","eslint":"^7.11.0","rimraf":"^3.0.0","typescript":"~4.1.5"},"gitHead":"f421e425f730a76a9f814e7e0bbd5266651fddd9","_id":"@amischencko/capacitor-oauth2@3.0.0","_nodeVersion":"12.13.0","_npmVersion":"6.11.2","dist":{"integrity":"sha512-wnVu7enJRegTDrhLhyhshz3hmt3Kl1Krzlrd+6LCd70RKQ5TwJ/1zgl9/3kFoHzAjYiXBExAE07YJrXo6wNwVA==","shasum":"eee453e37af47475ccf2432aeddf8ff1a68ee065","tarball":"https://registry.npmjs.org/@amischencko/capacitor-oauth2/-/capacitor-oauth2-3.0.0.tgz","fileCount":36,"unpackedSize":161885,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhBFT4CRA9TVsSAnZWagAA550QAISqTITtP8iI4GXz3ctp\n2wd1sBejn6yl/pVqspDueKHv2AwzA2tJWj4+e07NwHvsw8VCoIkS/IIgm10t\nAMtWSNnxLUufdla699lh4Og7HantmMA7QdNbDr0EFSbKAt3L5brxDKV/X+Ty\nPO7KrRppr2//nqyQAwan3kLS17yUyEZKopWNnhbOCK+jEKon45TWOeN02qVk\nsGwuxPa7Ei/d4rZFM9QJ360v5/0IsDwpRuIaPmvZlhQEHafDMt+cG53IPECY\nwffdeKicRRXQNJMorfU71pzaT/RCoK8uIOG6XhEw1Zi62073929X8dFSS54n\nOXRVBy+qZGnO7ZHRF+lECxKTY/YHnRHwOIV0vzH8oOfq+MJ3zyOq9/M+D+8U\n+jPODJXrDqdJhGTxBl946Aq78q2DYmtRPCkpK3qKsnae3/XgkdTgp8Ew/9ZX\nGgVbIFWG6pH7rduS8jO6oht92I90jUyyYUVIgyc2TN7YK6+AXAinAze+voS9\nrnNr2mJY9UUoeduLzDclT23wPIsjWkMtz94p6n0NcllutEMV6T7P03yIlVsV\no+4g6E5hXbIHG9F94Wzww01l/sh+ouIz8h8eOUSfuim/PqqNBf7W3Nf5v+C6\naZivBSrAnXnNVnUbapadPGCZQOvVDeMwDXU6tZxmXfcSyTWXY90uo4B9UBC+\nONKo\r\n=DwiI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCBYPUC8FHbrMS4Ti+MX3tNbEwvIdn4MYgQ+IJB1sK3YAIgXgO/HIlEPiA/jdaz8T94cAmHbIDVMx94/lf3hZudGhU="}]},"_npmUser":{"name":"amischenko","email":"a.mischencko@gmail.com"},"directories":{},"maintainers":[{"name":"amischenko","email":"a.mischencko@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/capacitor-oauth2_3.0.0_1627673847767_0.5776061026492325"},"_hasShrinkwrap":false}},"time":{"created":"2021-06-10T03:05:28.333Z","2.1.0":"2021-06-10T03:05:28.875Z","modified":"2022-04-04T13:49:36.764Z","3.0.0":"2021-07-30T19:37:28.012Z"},"maintainers":[{"name":"amischenko","email":"a.mischencko@gmail.com"}],"description":"Capacitor OAuth 2 client plugin","homepage":"https://github.com/amischenko/capacitor-oauth2","keywords":["capacitor","capacitor-plugin","oauth2","oauth2-client","social-login"],"repository":{"type":"git","url":"git+https://github.com/amischenko/capacitor-oauth2.git"},"author":{"name":"Michael Oberwasserlechner"},"bugs":{"url":"https://github.com/amischenko/capacitor-oauth2/issues"},"license":"MIT","readme":"# Capacitor OAuth 2 client plugin\r\n\r\n<a href=\"https://github.com/moberwasserlechner/capacitor-oauth2/actions?query=workflow%3ACI\"><img src=\"https://img.shields.io/github/workflow/status/moberwasserlechner/capacitor-oauth2/CI?style=flat-square\" /></a>\r\n<a href=\"https://www.npmjs.com/package/@byteowls/capacitor-oauth2\"><img src=\"https://img.shields.io/npm/dw/@byteowls/capacitor-oauth2?style=flat-square\" /></a>\r\n<a href=\"https://www.npmjs.com/package/@byteowls/capacitor-oauth2\"><img src=\"https://img.shields.io/npm/v/@byteowls/capacitor-oauth2?style=flat-square\" /></a>\r\n<a href=\"https://www.npmjs.com/package/@byteowls/capacitor-oauth2\"><img src=\"https://img.shields.io/npm/l/@byteowls/capacitor-oauth2?style=flat-square\" /></a>\r\n\r\nThis a generic OAuth 2 client plugin.\r\n\r\nIt let you configure the oauth parameters yourself instead of using SDKs. Therefore it is usable with various providers.\r\nSee [providers](#list-of-providers) the community has already used this plugin with.\r\n\r\n## Maintainers\r\n\r\n| Maintainer | GitHub | Social |\r\n| -----------| -------| -------|\r\n| Michael Oberwasserlechner | [moberwasserlechner](https://github.com/moberwasserlechner) | [@michaelowl_web](https://twitter.com/michaelowl_web) |\r\n\r\nActively maintained: YES\r\n\r\n## Install\r\n\r\n```bash\r\nnpm install @capacitor-community/oauth2\r\nnpx cap sync\r\n```\r\n\r\n## Versions\r\n\r\n| Plugin | Minimum Capacitor | Docs                                                                                   | Notes                          |\r\n|--------|-------------------|----------------------------------------------------------------------------------------|--------------------------------|\r\n| 3.x    | 3.0.0             | **(NOT RELEASED YET)** [README](https://github.com/moberwasserlechner/oauth2/blob/master/README.md)           | Breaking changes see Changelog. XCode 12.0 needs this version  |\r\n| 2.x    | 2.0.0             | [README](https://github.com/moberwasserlechner/capacitor-oauth2/blob/2.1.0/README.md)  | Breaking changes see Changelog. XCode 11.4 needs this version  |\r\n| 1.x    | 1.0.0             | [README](https://github.com/moberwasserlechner/capacitor-oauth2/blob/1.1.0/README.md)  |                                |\r\n\r\nFor further details on what has changed see the [CHANGELOG](https://github.com/moberwasserlechner/capacitor-oauth2/blob/master/CHANGELOG.md).\r\n\r\n## Supported flows\r\n\r\nSee the excellent article about OAuth2 response type combinations.\r\n\r\nhttps://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660\r\n\r\nThe plugin on the other will behave differently depending on the existence of certain config parameters:\r\n\r\nThese parameters are:\r\n\r\n* `accessTokenEndpoint`\r\n* `resourceUrl`\r\n\r\ne.g.\r\n\r\n1)\r\nIf `responseType=code`, `pkceDisable=true` and `accessTokenEndpoint` is missing the `authorizationCode` will be resolve along with the whole authorization response.\r\nThis only works for the Web and Android. On iOS the used lib does not allows to cancel after the authorization request see #13.\r\n\r\n2)\r\nIf you just need the `id_token` JWT you have to set `accessTokenEndpoint` and `resourceUrl` to `null`.\r\n\r\n\r\n### Tested / working flows\r\n\r\nThese flows are already working and were tested by me.\r\n\r\n#### Implicit flow\r\n\r\n```\r\nresponseType: \"token\"\r\n```\r\n\r\n#### Code flow + PKCE\r\n\r\n```\r\n...\r\nresponseType: \"code\"\r\npkceEnable: true\r\n...\r\n```\r\n\r\nPlease be aware that some providers (OneDrive, Auth0) allow **Code Flow + PKCE** only for native apps. Web apps have to use implicit flow.\r\n\r\n### Important\r\nFor security reasons this plugin does/will not support Code Flow without PKCE.\r\n\r\nThat would include storing your **client secret** in client code which is highly insecure and not recommended.\r\nThat flow should only be used on the backend (server).\r\n\r\n## Configuration\r\n\r\nStarting with version 3.0.0, the plugin is registered automatically on all platforms.\r\n\r\n### Use it\r\n\r\n```typescript\r\nimport {OAuth2Client} from \"@byteowls/capacitor-oauth2\";\r\n\r\n@Component({\r\n  template: '<button (click)=\"onOAuthBtnClick()\">Login with OAuth</button>' +\r\n   '<button (click)=\"onOAuthRefreshBtnClick()\">Refresh token</button>' +\r\n   '<button (click)=\"onLogoutClick()\">Logout OAuth</button>'\r\n})\r\nexport class SignupComponent {\r\n    refreshToken: string;\r\n\r\n    onOAuthBtnClick() {\r\n        OAuth2Client.authenticate(\r\n            oauth2Options\r\n        ).then(response => {\r\n            let accessToken = response[\"access_token\"];\r\n            this.refreshToken = response[\"refresh_token\"];\r\n\r\n            // only if you include a resourceUrl protected user values are included in the response!\r\n            let oauthUserId = response[\"id\"];\r\n            let name = response[\"name\"];\r\n\r\n            // go to backend\r\n        }).catch(reason => {\r\n            console.error(\"OAuth rejected\", reason);\r\n        });\r\n    }\r\n\r\n    // Refreshing tokens only works on iOS/Android for now\r\n    onOAuthRefreshBtnClick() {\r\n      if (!this.refreshToken) {\r\n        console.error(\"No refresh token found. Log in with OAuth first.\");\r\n      }\r\n\r\n      OAuth2Client.refreshToken(\r\n        oauth2RefreshOptions\r\n      ).then(response => {\r\n        let accessToken = response[\"access_token\"];\r\n        // Don't forget to store the new refresh token as well!\r\n        this.refreshToken = response[\"refresh_token\"];\r\n        // Go to backend\r\n      }).catch(reason => {\r\n          console.error(\"Refreshing token failed\", reason);\r\n      });\r\n    }\r\n\r\n    onLogoutClick() {\r\n            OAuth2Client.logout(\r\n                oauth2LogoutOptions\r\n            ).then(() => {\r\n                // do something\r\n            }).catch(reason => {\r\n                console.error(\"OAuth logout failed\", reason);\r\n            });\r\n        }\r\n}\r\n```\r\n\r\n### Options\r\n\r\nSee the `oauth2Options` and `oauth2RefreshOptions` interfaces at https://github.com/moberwasserlechner/capacitor-oauth2/blob/master/src/definitions.ts for details.\r\n\r\nExample:\r\n```\r\n{\r\n      authorizationBaseUrl: \"https://accounts.google.com/o/oauth2/auth\",\r\n      accessTokenEndpoint: \"https://www.googleapis.com/oauth2/v4/token\",\r\n      scope: \"email profile\",\r\n      resourceUrl: \"https://www.googleapis.com/userinfo/v2/me\",\r\n      web: {\r\n        appId: environment.oauthAppId.google.web,\r\n        responseType: \"token\", // implicit flow\r\n        accessTokenEndpoint: \"\", // clear the tokenEndpoint as we know that implicit flow gets the accessToken from the authorizationRequest\r\n        redirectUrl: \"http://localhost:4200\",\r\n        windowOptions: \"height=600,left=0,top=0\"\r\n      },\r\n      android: {\r\n        appId: environment.oauthAppId.google.android,\r\n        responseType: \"code\", // if you configured a android app in google dev console the value must be \"code\"\r\n        redirectUrl: \"com.companyname.appname:/\" // package name from google dev console\r\n      },\r\n      ios: {\r\n        appId: environment.oauthAppId.google.ios,\r\n        responseType: \"code\", // if you configured a ios app in google dev console the value must be \"code\"\r\n        redirectUrl: \"com.companyname.appname:/\" // Bundle ID from google dev console\r\n      }\r\n    }\r\n ```\r\n\r\n\r\n#### authenticate() and logout()\r\n\r\n**Overrideable Base Parameter**\r\n\r\nThese parameters are overrideable in every platform\r\n\r\n| parameter            \t| default \t| required \t| description                                                                                                                                                                                                                            \t| since \t|\r\n|----------------------\t|---------\t|----------\t|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\t|-------\t|\r\n| appId                \t|         \t| yes      \t| aka clientId, serviceId, ...                                                                                                                                                                                                           \t|       \t|\r\n| authorizationBaseUrl \t|         \t| yes      \t|                                                                                                                                                                                                                                        \t|       \t|\r\n| responseType         \t|         \t| yes      \t|                                                                                                                                                                                                                                        \t|       \t|\r\n| redirectUrl          \t|         \t| yes      \t|                                                                                                                                                                                                                                        \t| 2.0.0 \t|\r\n| accessTokenEndpoint  \t|         \t|          \t| If empty the authorization response incl code is returned. Known issue: Not on iOS!                                                                                                                                                    \t|       \t|\r\n| resourceUrl          \t|         \t|          \t| If empty the tokens are return instead. If you need just the `id_token` you have to set both `accessTokenEndpoint` and `resourceUrl` to `null` or empty ``.                                  |       \t|\r\n| pkceEnabled          \t| `false` \t|          \t| Enable PKCE if you need it.                                                                                                                                                                                                            \t|       \t|\r\n| scope                \t|         \t|          \t|                                                                                                                                                                                                                                        \t|       \t|\r\n| state                \t|         \t|          \t| The plugin always uses a state.<br>If you don't provide one we generate it.                                                                                                                                                            \t|       \t|\r\n| additionalParameters \t|         \t|          \t| Additional parameters for anything you might miss, like `none`, `response_mode`. <br><br>Just create a key value pair.<br>```{ \"key1\": \"value\", \"key2\": \"value, \"response_mode\": \"value\"}``` \t|       \t|\r\n\r\n**Platform Web**\r\n\r\n| parameter     \t| default \t| required \t| description                            \t| since \t|\r\n|---------------\t|---------\t|----------\t|----------------------------------------\t|-------\t|\r\n| windowOptions \t|         \t|          \t| e.g. width=500,height=600,left=0,top=0 \t|       \t|\r\n| windowTarget  \t| `_blank`  |       \t|                                        \t|       \t|\r\n| windowReplace  \t|           |       \t|                                        \t| 3.0.0   \t|\r\n\r\n**Platform Android**\r\n\r\n| parameter                    \t| default \t| required \t| description                                                                                                              \t| since \t|\r\n|------------------------------\t|---------\t|----------\t|--------------------------------------------------------------------------------------------------------------------------\t|-------\t|\r\n| customHandlerClass           \t|         \t|          \t| Provide a class name implementing `com.byteowls.capacitor.oauth2.handler.OAuth2CustomHandler`                            \t|       \t|\r\n| handleResultOnNewIntent      \t| `false` \t|          \t| Alternative to handle the activity result. The `onNewIntent` method is only call if the App was killed while logging in. \t|       \t|\r\n| handleResultOnActivityResult \t| `true`  \t|          \t|                                                                                                                          \t|       \t|\r\n\r\n**Platform iOS**\r\n\r\n| parameter          \t| default \t| required \t| description                                                                                    \t| since \t|\r\n|--------------------\t|---------\t|----------\t|------------------------------------------------------------------------------------------------\t|-------\t|\r\n| customHandlerClass \t|         \t|          \t| Provide a class name implementing `ByteowlsCapacitorOauth2.OAuth2CustomHandler`                \t|       \t|\r\n| siwaUseScope       \t|         \t|          \t| SiWA default scope is `name email` if you want to use the configured one set this param `true` \t| 2.1.0 \t|\r\n\r\n\r\n#### refreshToken()\r\n\r\n| parameter           \t| default \t| required \t| description                  \t| since \t|\r\n|---------------------\t|---------\t|----------\t|------------------------------\t|-------\t|\r\n| appId               \t|         \t| yes      \t| aka clientId, serviceId, ... \t|       \t|\r\n| accessTokenEndpoint \t|         \t| yes      \t|                              \t|       \t|\r\n| refreshToken        \t|         \t| yes      \t|                              \t|       \t|\r\n| scope               \t|         \t|          \t|                              \t|       \t|\r\n\r\n### Error Codes\r\n\r\n#### authenticate()\r\n\r\n* ERR_PARAM_NO_APP_ID ... The appId / clientId is missing. (web, android, ios)\r\n* ERR_PARAM_NO_AUTHORIZATION_BASE_URL ... The authorization base url is missing. (web, android, ios)\r\n* ERR_PARAM_NO_RESPONSE_TYPE ... The response type is missing. (web, android, ios)\r\n* ERR_PARAM_NO_REDIRECT_URL ... The redirect url is missing. (web, android, ios)\r\n* ERR_STATES_NOT_MATCH ... The state included in the authorization code request does not match the one in the redirect. Security risk! (web, android, ios)\r\n* ERR_AUTHORIZATION_FAILED ... The authorization failed.\r\n* ERR_NO_ACCESS_TOKEN ... No access_token found. (web, android)\r\n* ERR_NO_AUTHORIZATION_CODE ... No authorization code was returned in the redirect response. (web, android, ios)\r\n* USER_CANCELLED ... The user cancelled the login flow. (web, android, ios)\r\n* ERR_CUSTOM_HANDLER_LOGIN ... Login through custom handler class failed. See logs and check your code. (android, ios)\r\n* ERR_CUSTOM_HANDLER_LOGOUT ... Logout through custom handler class failed. See logs and check your code. (android, ios)\r\n* ERR_ANDROID_NO_BROWSER ... No suitable browser could be found! (Android)\r\n* ERR_ANDROID_RESULT_NULL ... The auth result is null. The intent in the ActivityResult is null. This might be a valid state but make sure you configured Android part correctly! See [Platform Android](#platform-android)\r\n* ERR_GENERAL ... A unspecific error. Check the logs to see want exactly happened. (web, android, ios)\r\n\r\n#### refreshToken()\r\n\r\n* ERR_PARAM_NO_APP_ID ... The appId / clientId is missing. (android, ios)\r\n* ERR_PARAM_NO_ACCESS_TOKEN_ENDPOINT ... The access token endpoint url is missing. It is only needed on refresh, on authenticate it is optional. (android, ios)\r\n* ERR_PARAM_NO_REFRESH_TOKEN ... The refresh token is missing. (android, ios)\r\n* ERR_NO_ACCESS_TOKEN ... No access_token found. (web, android)\r\n* ERR_GENERAL ... A unspecific error. Check the logs to see want exactly happened. (android, ios)\r\n\r\n## Platform: Web/PWA\r\n\r\nThis implementation just opens a browser window to let users enter their credentials.\r\n\r\nAs there is no provider SDK used to accomplish OAuth, no additional javascript files must be loaded and so there is no performance\r\nimpact using this plugin in a web application.\r\n\r\n### Register plugin\r\nOn Web/PWA the plugin is registered **automatically** by Capacitor.\r\n\r\n## Platform: Android\r\n\r\nPrerequisite: [Capacitor Android Docs](https://capacitor.ionicframework.com/docs/android/configuration)\r\n\r\n### Register plugin\r\nOn Android the plugin is registered **automatically** by Capacitor.\r\n\r\n### Android Default Config\r\n\r\nSkip this, if you use a [OAuth2CustomHandler](#custom-oauth-handler)\r\n\r\n#### android/app/src/main/res/AndroidManifest.xml\r\n\r\nThe `AndroidManifest.xml` in your Capacitor Android project already contains\r\n```xml\r\n    <intent-filter>\r\n        <action android:name=\"android.intent.action.VIEW\" />\r\n        <category android:name=\"android.intent.category.DEFAULT\" />\r\n        <category android:name=\"android.intent.category.BROWSABLE\" />\r\n        <data android:scheme=\"@string/custom_url_scheme\" />\r\n    </intent-filter>\r\n```\r\n\r\nFind the following line in your `AndroidManifest.xml`\r\n```xml\r\n<data android:scheme=\"@string/custom_url_scheme\" />\r\n```\r\nand change it to\r\n```xml\r\n<data android:scheme=\"@string/custom_url_scheme\" android:host=\"oauth\" />\r\n```\r\nNote: Actually any value for `android:host` will do. It does not has to be `oauth`.\r\n\r\nThis will fix an issues within the oauth workflow when the application is shown twice.\r\nSee [Issue #15](https://github.com/moberwasserlechner/capacitor-oauth2/issues/15) for details what happens.\r\n\r\n#### android/app/src/main/res/values/strings.xml\r\n\r\nIn your `strings.xml` change the `custom_url_scheme` string to your actual scheme value. Do NOT include `://oauth/redirect` or other endpoint urls here!\r\n\r\n```xml\r\n<string name=\"custom_url_scheme\">com.example.yourapp</string>\r\n\r\n<!-- wrong -->\r\n<!-- <string name=\"custom_url_scheme\">com.example.yourapp://endpoint/path</string> -->\r\n```\r\n\r\n#### android/app/build.gradle\r\n\r\n```groovy\r\nandroid.defaultConfig.manifestPlaceholders = [\r\n  // change to the 'custom_url_scheme' value in your strings.xml. They need to be the same. e.g.\r\n  \"appAuthRedirectScheme\": \"com.example.yourapp\"\r\n]\r\n```\r\n\r\n**Troubleshooting**\r\n\r\n1) If your `appAuthRedirectScheme` does not get recognized because you are using a library that replaces it\r\n(e.g.: onesignal-cordova-plugin), you will have to add it to your `buildTypes` like the following:\r\n\r\n```groovy\r\nandroid.buildTypes.debug.manifestPlaceholders =  [\r\n  'appAuthRedirectScheme': '<@string/custom_url_scheme from string.xml>' // e.g. com.companyname.appname\r\n]\r\nandroid.buildTypes.release.manifestPlaceholders = [\r\n  'appAuthRedirectScheme': '<@string/custom_url_scheme from string.xml>' // e.g. com.companyname.appname\r\n]\r\n```\r\n\r\n2) \"ERR_ANDROID_RESULT_NULL\": See [Issue #52](https://github.com/moberwasserlechner/capacitor-oauth2/issues/52#issuecomment-525715515) for details.\r\nI cannot reproduce this behaviour. Moreover there might be situation this state is valid. In other cases e.g. in the linked issue a configuration tweak fixed it.\r\n\r\n### Custom OAuth Handler\r\n\r\nSome OAuth provider (Facebook) force developers to use their SDK on Android.\r\n\r\nThis plugin should be as generic as possible so I don't want to include provider specific dependencies.\r\n\r\nTherefore I created a mechanism which let developers integrate custom SDK features in this plugin.\r\nSimply configure a full qualified classname in the option property `android.customHandlerClass`.\r\nThis class has to implement `com.byteowls.capacitor.oauth2.handler.OAuth2CustomHandler`.\r\n\r\nSee a full working example below!\r\n\r\n## Platform: iOS\r\n\r\n### Register plugin\r\nOn iOS the plugin is registered **automatically** by Capacitor.\r\n\r\n### iOS Default Config\r\n\r\nSkip this, if you use a [OAuth2CustomHandler](#custom-oauth-handler-1)\r\n\r\nOpen `ios/App/App/Info.plist` in XCode (Context menu -> Open as -> Source) and add the value of `redirectUrl` from your config without `:/` like that\r\n\r\n```xml\r\n\t<key>CFBundleURLTypes</key>\r\n\t<array>\r\n\t\t<dict>\r\n\t\t\t<key>CFBundleURLSchemes</key>\r\n\t\t\t<array>\r\n\t\t\t\t<string>com.companyname.appname</string>\r\n\t\t\t</array>\r\n\t\t</dict>\r\n\t</array>\r\n```\r\n\r\n### Custom OAuth Handler\r\n\r\nSome OAuth provider (e.g. Facebook) force developers to use their SDK on iOS.\r\n\r\nThis plugin should be as generic as possible so I don't want to include provider specific dependencies.\r\n\r\nTherefore I created a mechanism which let developers integrate custom SDK features in this plugin.\r\nSimply configure a the class name in the option property `ios.customHandlerClass`.\r\nThis class has to implement `ByteowlsCapacitorOauth2.OAuth2CustomHandler`.\r\n\r\nSee a full working example below!\r\n\r\n\r\n## Platform: Electron\r\n\r\n- No timeline.\r\n\r\n## List of Providers\r\n\r\nThese are some of the providers that can be configured with this plugin. I'm happy to add others ot the list, if you let me know.\r\n\r\n| Name      | Example (config,...)   | Notes |\r\n|-----------|------------------------|-------|\r\n| Google    | [see below](#google)   |       |\r\n| Facebook  | [see below](#facebook) |       |\r\n| Azure B2C | [see below](#azure-b2c)|       |\r\n| Apple     | [see below](#apple)    | ios only |\r\n\r\n\r\n## Examples\r\n\r\n### Apple\r\n\r\n#### iOS 13+\r\nMinimum config\r\n\r\n```typescript\r\nappleLogin() {\r\n  OAuth2Client.authenticate({\r\n    appId: \"xxxxxxxxx\",\r\n    authorizationBaseUrl: \"https://appleid.apple.com/auth/authorize\",\r\n  });\r\n}\r\n```\r\n\r\nThe plugin requires `authorizationBaseUrl` as it triggers the native support and because it is needed for other platforms anyway. Those platforms are not supported yet.\r\n\r\n`appId` is required as well for internal, generic reasons and any not blank value is fine.\r\n\r\nIt is also possible to control the scope although Apple only supports `email` and/or `fullName`. Add `siwaUseScope: true` to the ios block\r\nand then you can use `scope: \"fullName\"`, `scope: \"email\"` or both but the latter is the default one if `siwaUseScope` is not set or false.\r\n\r\n```typescript\r\nappleLogin() {\r\n  OAuth2Client.authenticate({\r\n    appId: \"xxxxxxxxx\",\r\n    authorizationBaseUrl: \"https://appleid.apple.com/auth/authorize\",\r\n    ios: {\r\n      siwaUseScope: true,\r\n      scope: \"fullName\"\r\n    }\r\n  });\r\n}\r\n```\r\n\r\nAs \"Signin with Apple\" is only supported since iOS 13 you should show the according button only in that case.\r\n\r\nIn Angular do sth like\r\n```typescript\r\nimport {Component, OnInit} from '@angular/core';\r\nimport {Device, DeviceInfo} from \"@capacitor/device\";\r\nimport {OAuth2Client} from \"@byteowls/capacitor-oauth2\";\r\n\r\n@Component({\r\n  templateUrl: './siwa.component.html'\r\n})\r\nexport class SiwaComponent implements OnInit {\r\n\r\n  ios: boolean;\r\n  siwaSupported: boolean;\r\n  deviceInfo: DeviceInfo;\r\n\r\n  async ngOnInit() {\r\n      this.deviceInfo = await Device.getInfo();\r\n      this.ios = this.deviceInfo.platform === \"ios\";\r\n      if (this.ios) {\r\n          const majorVersion: number = +this.deviceInfo.osVersion.split(\".\")[0];\r\n          this.siwaSupported = majorVersion >= 13;\r\n      }\r\n  }\r\n}\r\n\r\n```\r\n\r\nAnd show the button only if `siwaSupported` is `true`.\r\n\r\nThe response contains these fields:\r\n\r\n```\r\n\"id\"\r\n\"given_name\"\r\n\"family_name\"\r\n\"email\"\r\n\"real_user_status\"\r\n\"state\"\r\n\"id_token\"\r\n\"code\"\r\n```\r\n\r\n#### iOS <12\r\n\r\nnot supported\r\n\r\n#### PWA\r\n\r\nnot supported\r\n\r\n#### Android\r\n\r\nnot supported\r\n\r\n### Azure B2C\r\n\r\nIn case of problems please read [#91](https://github.com/moberwasserlechner/capacitor-oauth2/issues/91)\r\nand [#96](https://github.com/moberwasserlechner/capacitor-oauth2/issues/96)\r\n\r\nSee this [example repo](https://github.com/loonix/capacitor-oauth2-azure-example) by @loonix.\r\n\r\n#### PWA\r\n\r\nSee these 2 configs that should work.\r\n\r\nIt's important to use the urls you see in the Azure config for the specific platform.\r\n\r\n```typescript\r\nimport {OAuth2Client} from \"@byteowls/capacitor-oauth2\";\r\n\r\nazureLogin() {\r\n  OAuth2Client.authenticate({\r\n    appId: \"xxxxxxxxx\",\r\n    authorizationBaseUrl: \"https://tenantb2c.b2clogin.com/tfp/tenantb2c.onmicrosoft.com/B2C_1_SignUpAndSignIn/oauth2/v2.0/authorize\",\r\n    accessTokenEndpoint: \"\",\r\n    scope: \"openid offline_access https://tenantb2c.onmicrosoft.com/capacitor-api/demo.read\",\r\n    responseType: \"token\",\r\n    web: {\r\n        redirectUrl: \"http://localhost:8100/auth\"\r\n    },\r\n    android: {\r\n        pkceEnabled: true,\r\n        responseType: \"code\",\r\n        redirectUrl: \"com.tenant.app://oauth/auth\", // Use the value from Azure config. Platform \"Android\"\r\n        accessTokenEndpoint: \"https://tenantb2c.b2clogin.com/tfp/tenantb2c.onmicrosoft.com/B2C_1_SignUpAndSignIn/oauth2/v2.0/token\",\r\n        handleResultOnNewIntent: true,\r\n        handleResultOnActivityResult: true\r\n    },\r\n    ios: {\r\n        pkceEnabled: true,\r\n        responseType: \"code\",\r\n        redirectUrl: \"msauth.BUNDLE_ID://oauth\", // Use the value from Azure config. Platform \"iOS/Mac\"\r\n        accessTokenEndpoint: \"https://tenantb2c.b2clogin.com/tfp/tenantb2c.onmicrosoft.com/B2C_1_SignUpAndSignIn/oauth2/v2.0/token\",\r\n    }\r\n  });\r\n}\r\n```\r\n\r\n```typescript\r\nimport {OAuth2Client} from \"@byteowls/capacitor-oauth2\";\r\n\r\nazureLogin() {\r\n  OAuth2Client.authenticate({\r\n    appId: 'XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXX',\r\n    authorizationBaseUrl: 'https://TENANT.b2clogin.com/tfp/TENANT.onmicrosoft.com/B2C_1_policy-signin-signup-web/oauth2/v2.0/authorize',\r\n    accessTokenEndpoint: '',\r\n    scope: 'https://XXXXXXX.onmicrosoft.com/TestApi4/demo.read',\r\n    responseType: 'token',\r\n    web: {\r\n      redirectUrl: 'http://localhost:8100/'\r\n    },\r\n    android: {\r\n      pkceEnabled: true,\r\n      responseType: 'code',\r\n      redirectUrl: 'com.company.project://oauth/redirect',\r\n      accessTokenEndpoint: 'https://TENANT.b2clogin.com/TENANT.onmicrosoft.com/B2C_1_policy-signin-signup-web',\r\n      handleResultOnNewIntent: true,\r\n      handleResultOnActivityResult: true\r\n    },\r\n    ios: {\r\n      pkceEnabled: true,\r\n      responseType: 'code',\r\n      redirectUrl: 'com.company.project://oauth',\r\n      accessTokenEndpoint: 'https://TENANT.b2clogin.com/TENANT.onmicrosoft.com/B2C_1_policy-signin-signup-web',\r\n    }\r\n  });\r\n}\r\n```\r\n\r\n#### Android\r\n\r\nSee [Android Default Config](#android-default-config)\r\n\r\n#### iOS\r\n\r\nOpen `Info.plist` in XCode by Right Click on that file -> Open as -> Source Code. Note: XCode does not \"like\" files opened and changed externally.\r\n\r\n```xml\r\n\t<key>CFBundleURLTypes</key>\r\n\t<array>\r\n\t\t<dict>\r\n\t\t\t<key>CFBundleURLSchemes</key>\r\n\t\t\t<array>\r\n\t\t\t\t<string>msauth.BUNDLE_ID</string>\r\n\t\t\t</array>\r\n\t\t</dict>\r\n\t</array>\r\n```\r\n\r\nDo not enter `://` and part of your redirect url after those chars.\r\n\r\n### Google\r\n\r\n#### PWA\r\n```typescript\r\nimport {OAuth2Client} from \"@byteowls/capacitor-oauth2\";\r\n\r\ngoogleLogin() {\r\n    OAuth2Client.authenticate({\r\n      authorizationBaseUrl: \"https://accounts.google.com/o/oauth2/auth\",\r\n      accessTokenEndpoint: \"https://www.googleapis.com/oauth2/v4/token\",\r\n      scope: \"email profile\",\r\n      resourceUrl: \"https://www.googleapis.com/userinfo/v2/me\",\r\n      web: {\r\n        appId: environment.oauthAppId.google.web,\r\n        responseType: \"token\", // implicit flow\r\n        accessTokenEndpoint: \"\", // clear the tokenEndpoint as we know that implicit flow gets the accessToken from the authorizationRequest\r\n        redirectUrl: \"http://localhost:4200\",\r\n        windowOptions: \"height=600,left=0,top=0\"\r\n      },\r\n      android: {\r\n        appId: environment.oauthAppId.google.android,\r\n        responseType: \"code\", // if you configured a android app in google dev console the value must be \"code\"\r\n        redirectUrl: \"com.companyname.appname:/\" // package name from google dev console\r\n      },\r\n      ios: {\r\n        appId: environment.oauthAppId.google.ios,\r\n        responseType: \"code\", // if you configured a ios app in google dev console the value must be \"code\"\r\n        redirectUrl: \"com.companyname.appname:/\" // Bundle ID from google dev console\r\n      }\r\n    }).then(resourceUrlResponse => {\r\n      // do sth e.g. check with your backend\r\n    }).catch(reason => {\r\n      console.error(\"Google OAuth rejected\", reason);\r\n    });\r\n  }\r\n```\r\n\r\n#### Android\r\n\r\nSee [Android Default Config](#android-default-config)\r\n\r\n#### iOS\r\n\r\nSee [iOS Default Config](#ios-default-config)\r\n\r\n### Facebook\r\n\r\n#### PWA\r\n\r\n```typescript\r\nimport {OAuth2Client} from \"@byteowls/capacitor-oauth2\";\r\n\r\nfacebookLogin() {\r\n    let fbApiVersion = \"2.11\";\r\n    OAuth2Client.authenticate({\r\n      appId: \"YOUR_FACEBOOK_APP_ID\",\r\n      authorizationBaseUrl: \"https://www.facebook.com/v\" + fbApiVersion + \"/dialog/oauth\",\r\n      resourceUrl: \"https://graph.facebook.com/v\" + fbApiVersion + \"/me\",\r\n      web: {\r\n        responseType: \"token\",\r\n        redirectUrl: \"http://localhost:4200\",\r\n        windowOptions: \"height=600,left=0,top=0\"\r\n      },\r\n      android: {\r\n        customHandlerClass: \"com.companyname.appname.YourAndroidFacebookOAuth2Handler\",\r\n      },\r\n      ios: {\r\n        customHandlerClass: \"App.YourIOsFacebookOAuth2Handler\",\r\n      }\r\n    }).then(resourceUrlResponse => {\r\n      // do sth e.g. check with your backend\r\n    }).catch(reason => {\r\n      console.error(\"FB OAuth rejected\", reason);\r\n    });\r\n  }\r\n```\r\n\r\n**Android and iOS**\r\n\r\nSince October 2018 Strict Mode for Redirect Urls is always on.\r\n\r\n>Use Strict Mode for Redirect URIs\r\n\r\n>Only allow redirects that use the Facebook SDK or that exactly match the Valid OAuth Redirect URIs. Strongly recommended.\r\n\r\nBefore that it was able to use `fb<your_app_id>:/authorize` in a Android or iOS app and get the accessToken.\r\n\r\nUnfortunately now we have to use the SDK for Facebook Login.\r\n\r\nI don't want to have a dependency to facebook for users, who don't need Facebook OAuth.\r\n\r\nTo address this problem I created a integration with custom code in your app `customHandlerClass`\r\n\r\n#### Android\r\n\r\nSee https://developers.facebook.com/docs/facebook-login/android/ for more background on how to configure Facebook in your Android app.\r\n\r\n1) Add `implementation 'com.facebook.android:facebook-login:4.36.0'` to `android/app/build.gradle` as dependency.\r\n\r\n2) Add to `string.xml`\r\n\r\n```xml\r\n    <string name=\"facebook_app_id\"><YOUR_FACEBOOK_APP_ID></string>\r\n    <string name=\"fb_login_protocol_scheme\">fb<YOUR_FACEBOOK_APP_ID></string>\r\n```\r\n\r\n3) Add to `AndroidManifest.xml`\r\n\r\n```xml\r\n<meta-data android:name=\"com.facebook.sdk.ApplicationId\" android:value=\"@string/facebook_app_id\"/>\r\n\r\n<activity android:name=\"com.facebook.FacebookActivity\"\r\n  android:configChanges=\r\n    \"keyboard|keyboardHidden|screenLayout|screenSize|orientation\"\r\n  android:label=\"@string/app_name\" />\r\n\r\n<activity android:name=\"com.facebook.CustomTabActivity\" android:exported=\"true\">\r\n  <intent-filter>\r\n    <action android:name=\"android.intent.action.VIEW\" />\r\n    <category android:name=\"android.intent.category.DEFAULT\" />\r\n    <category android:name=\"android.intent.category.BROWSABLE\" />\r\n    <data android:scheme=\"@string/fb_login_protocol_scheme\" />\r\n  </intent-filter>\r\n</activity>\r\n```\r\n4) Create a custom handler class\r\n\r\n```java\r\n\r\npackage com.companyname.appname;\r\n\r\nimport android.app.Activity;\r\n\r\nimport com.byteowls.capacitor.oauth2.handler.AccessTokenCallback;\r\nimport com.byteowls.capacitor.oauth2.handler.OAuth2CustomHandler;\r\nimport com.companyname.appname.MainActivity;\r\nimport com.facebook.AccessToken;\r\nimport com.facebook.FacebookCallback;\r\nimport com.facebook.FacebookException;\r\nimport com.facebook.login.DefaultAudience;\r\nimport com.facebook.login.LoginBehavior;\r\nimport com.facebook.login.LoginManager;\r\nimport com.facebook.login.LoginResult;\r\nimport com.getcapacitor.PluginCall;\r\n\r\nimport java.util.Collections;\r\n\r\npublic class YourAndroidFacebookOAuth2Handler implements OAuth2CustomHandler {\r\n\r\n  @Override\r\n  public void getAccessToken(Activity activity, PluginCall pluginCall, final AccessTokenCallback callback) {\r\n    AccessToken accessToken = AccessToken.getCurrentAccessToken();\r\n    if (AccessToken.isCurrentAccessTokenActive()) {\r\n      callback.onSuccess(accessToken.getToken());\r\n    } else {\r\n      LoginManager l = LoginManager.getInstance();\r\n      l.logInWithReadPermissions(activity, Collections.singletonList(\"public_profile\"));\r\n      l.setLoginBehavior(LoginBehavior.WEB_ONLY);\r\n      l.setDefaultAudience(DefaultAudience.NONE);\r\n      LoginManager.getInstance().registerCallback(((MainActivity) activity).getCallbackManager(), new FacebookCallback<LoginResult>() {\r\n        @Override\r\n        public void onSuccess(LoginResult loginResult) {\r\n          callback.onSuccess(loginResult.getAccessToken().getToken());\r\n        }\r\n\r\n        @Override\r\n        public void onCancel() {\r\n          callback.onCancel();\r\n        }\r\n\r\n        @Override\r\n        public void onError(FacebookException error) {\r\n          callback.onCancel();\r\n        }\r\n      });\r\n    }\r\n\r\n  }\r\n\r\n  @Override\r\n  public boolean logout(Activity activity, PluginCall pluginCall) {\r\n    LoginManager.getInstance().logOut();\r\n    return true;\r\n  }\r\n}\r\n\r\n```\r\n5) Change your MainActivity like\r\n\r\n```java\r\npublic class MainActivity extends BridgeActivity {\r\n\r\n  private CallbackManager callbackManager;\r\n\r\n  @Override\r\n  public void onCreate(Bundle savedInstanceState) {\r\n    super.onCreate(savedInstanceState);\r\n    // Initialize Facebook SDK\r\n    FacebookSdk.sdkInitialize(this.getApplicationContext());\r\n    callbackManager = CallbackManager.Factory.create();\r\n  }\r\n\r\n  @Override\r\n  protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r\n    super.onActivityResult(requestCode, resultCode, data);\r\n    if (callbackManager.onActivityResult(requestCode, resultCode, data)) {\r\n      return;\r\n    }\r\n  }\r\n\r\n  public CallbackManager getCallbackManager() {\r\n    return callbackManager;\r\n  }\r\n\r\n}\r\n```\r\n\r\n**iOS**\r\n\r\nSee https://developers.facebook.com/docs/swift/getting-started and https://developers.facebook.com/docs/swift/login\r\n\r\n1) Add Facebook pods to `ios/App/Podfile` and run `pod install` afterwards\r\n\r\n```\r\nplatform :ios, '12.0'\r\nuse_frameworks!\r\n\r\n# workaround to avoid Xcode caching of Pods that requires\r\n# Product -> Clean Build Folder after new Cordova plugins installed\r\n# Requires CocoaPods 1.6 or newer\r\ninstall! 'cocoapods', :disable_input_output_paths => true\r\n\r\ndef capacitor_pods\r\n  pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'\r\n  pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'\r\n  pod 'ByteowlsCapacitorOauth2', :path => '../../node_modules/@byteowls/capacitor-oauth2'\r\n  # core plugins\r\n  pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'\r\n  pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device'\r\n  pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'\r\n  pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'\r\n  pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'\r\nend\r\n\r\ntarget 'App' do\r\n  capacitor_pods\r\n  # Add your Pods here\r\n  pod 'FacebookCore'\r\n  pod 'FacebookLogin'\r\nend\r\n```\r\n\r\n2) Add some Facebook configs to your `Info.plist`\r\n\r\n```xml\r\n<key>CFBundleURLTypes</key>\r\n<array>\r\n  <dict>\r\n    <key>CFBundleURLSchemes</key>\r\n    <array>\r\n      <string>fb{your-app-id}</string>\r\n    </array>\r\n  </dict>\r\n</array>\r\n<key>FacebookAppID</key>\r\n<string>{your-app-id}</string>\r\n<key>FacebookDisplayName</key>\r\n<string>{your-app-name}</string>\r\n<key>LSApplicationQueriesSchemes</key>\r\n<array>\r\n  <string>fbapi</string>\r\n  <string>fb-messenger-share-api</string>\r\n  <string>fbauth2</string>\r\n  <string>fbshareextension</string>\r\n</array>\r\n```\r\n\r\n3) Create a custom handler class\r\n\r\n```swift\r\nimport Foundation\r\nimport FacebookCore\r\nimport FacebookLogin\r\nimport Capacitor\r\nimport ByteowlsCapacitorOauth2\r\n\r\n@objc class YourIOsFacebookOAuth2Handler: NSObject, OAuth2CustomHandler {\r\n\r\n    required override init() {\r\n    }\r\n\r\n    func getAccessToken(viewController: UIViewController, call: CAPPluginCall, success: @escaping (String) -> Void, cancelled: @escaping () -> Void, failure: @escaping (Error) -> Void) {\r\n        if let accessToken = AccessToken.current {\r\n            success(accessToken.tokenString)\r\n        } else {\r\n            DispatchQueue.main.async {\r\n                let loginManager = LoginManager()\r\n                // I only need the most basic permissions but others are available\r\n                loginManager.logIn(permissions: [ .publicProfile ], viewController: viewController) { result in\r\n                    switch result {\r\n                    case .success(_, _, let accessToken):\r\n                        success(accessToken.tokenString)\r\n                    case .failed(let error):\r\n                        failure(error)\r\n                    case .cancelled:\r\n                        cancelled()\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    func logout(viewController: UIViewController, call: CAPPluginCall) -> Bool {\r\n        let loginManager = LoginManager()\r\n        loginManager.logOut()\r\n        return true\r\n    }\r\n}\r\n```\r\n\r\nThis handler will be automatically discovered up by the plugin and handles the login using the Facebook SDK.\r\nSee https://developers.facebook.com/docs/swift/login/#custom-login-button for details.\r\n\r\n4) The users that have redirect problem after success grant add the following code to `ios/App/App/AppDelegate.swift`.\r\nThis code correctly delegate the FB redirect url to be managed by Facebook SDK.\r\n\r\n```swift\r\nimport UIKit\r\nimport FacebookCore\r\nimport FacebookLogin\r\nimport Capacitor\r\n\r\n@UIApplicationMain\r\nclass AppDelegate: UIResponder, UIApplicationDelegate {\r\n\r\n    var window: UIWindow?\r\n\r\n    // other methods\r\n\r\n    func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {\r\n      // Called when the app was launched with a url. Feel free to add additional processing here,\r\n      // but if you want the App API to support tracking app url opens, make sure to keep this call\r\n\r\n      if let scheme = url.scheme, let host = url.host {\r\n        let appId: String = Settings.appID!\r\n        if scheme == \"fb\\(appId)\" && host == \"authorize\" {\r\n          return ApplicationDelegate.shared.application(app, open: url, options: options)\r\n        }\r\n      }\r\n\r\n      return CAPBridge.handleOpenUrl(url, options)\r\n    }\r\n\r\n    // other methods\r\n}\r\n```\r\n\r\n## Contribute\r\n\r\nSee [Contribution Guidelines](https://github.com/moberwasserlechner/capacitor-oauth2/blob/master/.github/CONTRIBUTING.md).\r\n\r\n## Changelog\r\nSee [CHANGELOG](https://github.com/moberwasserlechner/capacitor-oauth2/blob/master/CHANGELOG.md).\r\n\r\n## License\r\n\r\nMIT. See [LICENSE](https://github.com/moberwasserlechner/capacitor-oauth2/blob/master/LICENSE).\r\n\r\n## BYTEOWLS Software & Consulting\r\n\r\nThis plugin is powered by [BYTEOWLS Software & Consulting](https://byteowls.com).\r\n\r\nIf you need extended support for this project like critical changes or releases ahead of schedule. Feel free to contact us for a consulting offer.\r\n\r\n## Disclaimer\r\n\r\nWe have no business relation to Ionic.\r\n","readmeFilename":"README.md"}