From 38b65a40f7d199e8928af66c8cac7a6120f0f53e Mon Sep 17 00:00:00 2001 From: Tafel <35837839+tafelnl@users.noreply.github.com> Date: Fri, 3 May 2024 09:39:29 +0200 Subject: [PATCH] style: prettify readme (#261) --- README.md | 439 +++++++++++++++++++++++++++++------------------------- 1 file changed, 235 insertions(+), 204 deletions(-) diff --git a/README.md b/README.md index d2fc8e4b..486282d4 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,21 @@ See [identity providers](#list-of-providers) the community has already used this ## How to install For Capacitor v5 + ```bash npm i @capacitor-community/generic-oauth npx cap sync ``` For Capacitor v4 + ```bash npm i @capacitor-community/generic-oauth@4 npx cap sync ``` + For Capacitor v3 + ```bash npm i @capacitor-community/generic-oauth@3 npx cap sync @@ -31,7 +35,7 @@ npx cap sync ## Versions | Plugin | For Capacitor | Docs | Notes | -|--------|---------------|---------------------------------------------------------------------------------------|---------------------------------------------------------------| +| ------ | ------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | 5.x | 5.x.x | [README](./README.md) | Breaking changes see Changelog. XCode 14.1 needs this version | | 4.x | 4.x.x | [README](https://github.com/moberwasserlechner/capacitor-oauth2/blob/4.0.0/README.md) | Breaking changes see Changelog. XCode 12.0 needs this version | | 3.x | 3.x.x | [README](https://github.com/moberwasserlechner/capacitor-oauth2/blob/3.0.1/README.md) | Breaking changes see Changelog. XCode 12.0 needs this version | @@ -44,12 +48,12 @@ For further details on what has changed see the [CHANGELOG](https://github.com/m I would like to especially thank some people and companies for supporting my work on this plugin and therefore improving it for everybody. -* [Mark Laurence](https://github.com/UnclearMaker) and the [Royal Veterinary College](https://www.rvc.ac.uk/) - Thanks for supporting open source. +- [Mark Laurence](https://github.com/UnclearMaker) and the [Royal Veterinary College](https://www.rvc.ac.uk/) - Thanks for supporting open source. ## Maintainers -| Maintainer | GitHub | Social | -| -----------| -------| -------| +| Maintainer | GitHub | Social | +| ------------------------- | ----------------------------------------------------------- | ----------------------------------------------------- | | Michael Oberwasserlechner | [moberwasserlechner](https://github.com/moberwasserlechner) | [@michaelowl_web](https://twitter.com/michaelowl_web) | Actively maintained: YES @@ -64,18 +68,15 @@ The plugin on the other will behave differently depending on the existence of ce These parameters are: -* `accessTokenEndpoint` -* `resourceUrl` +- `accessTokenEndpoint` +- `resourceUrl` e.g. -1) -If `responseType=code`, `pkceDisable=true` and `accessTokenEndpoint` is missing the `authorizationCode` will be resolve along with the whole authorization response. -This only works for the Web and Android. On iOS the used lib does not allows to cancel after the authorization request see #13. - -2) -If you just need the `id_token` JWT you have to set `accessTokenEndpoint` and `resourceUrl` to `null`. +1. If `responseType=code`, `pkceDisable=true` and `accessTokenEndpoint` is missing the `authorizationCode` will be resolve along with the whole authorization response. + This only works for the Web and Android. On iOS the used lib does not allows to cancel after the authorization request see #13. +2. If you just need the `id_token` JWT you have to set `accessTokenEndpoint` and `resourceUrl` to `null`. ### Tested / working flows @@ -99,6 +100,7 @@ pkceEnable: true Please be aware that some providers (OneDrive, Auth0) allow **Code Flow + PKCE** only for native apps. Web apps have to use implicit flow. ### Important + For security reasons this plugin does/will not support Code Flow without PKCE. That would include storing your **client secret** in client code which is highly insecure and not recommended. @@ -111,62 +113,65 @@ Starting with version 3.0.0, the plugin is registered automatically on all platf ### Use it ```typescript -import {OAuth2Client} from "@capacitor-community/generic-oauth"; +import { OAuth2Client } from '@capacitor-community/generic-oauth'; @Component({ - template: '' + - '' + - '' + template: + '' + + '' + + '', }) export class SignupComponent { - accessToken: string; - refreshToken: string; - - onOAuthBtnClick() { - OAuth2Client.authenticate( - oauth2Options - ).then(response => { - this.accessToken = response["access_token"]; // storage recommended for android logout - this.refreshToken = response["refresh_token"]; - - // only if you include a resourceUrl protected user values are included in the response! - let oauthUserId = response["id"]; - let name = response["name"]; - - // go to backend - }).catch(reason => { - console.error("OAuth rejected", reason); - }); - } + accessToken: string; + refreshToken: string; + + onOAuthBtnClick() { + OAuth2Client.authenticate(oauth2Options) + .then(response => { + this.accessToken = response['access_token']; // storage recommended for android logout + this.refreshToken = response['refresh_token']; + + // only if you include a resourceUrl protected user values are included in the response! + let oauthUserId = response['id']; + let name = response['name']; + + // go to backend + }) + .catch(reason => { + console.error('OAuth rejected', reason); + }); + } - // Refreshing tokens only works on iOS/Android for now - onOAuthRefreshBtnClick() { - if (!this.refreshToken) { - console.error("No refresh token found. Log in with OAuth first."); - } + // Refreshing tokens only works on iOS/Android for now + onOAuthRefreshBtnClick() { + if (!this.refreshToken) { + console.error('No refresh token found. Log in with OAuth first.'); + } - OAuth2Client.refreshToken( - oauth2RefreshOptions - ).then(response => { - this.accessToken = response["access_token"]; // storage recommended for android logout + OAuth2Client.refreshToken(oauth2RefreshOptions) + .then(response => { + this.accessToken = response['access_token']; // storage recommended for android logout // Don't forget to store the new refresh token as well! - this.refreshToken = response["refresh_token"]; + this.refreshToken = response['refresh_token']; // Go to backend - }).catch(reason => { - console.error("Refreshing token failed", reason); + }) + .catch(reason => { + console.error('Refreshing token failed', reason); }); - } + } - onLogoutClick() { - OAuth2Client.logout( - oauth2LogoutOptions, - this.accessToken // only used on android - ).then(() => { - // do something - }).catch(reason => { - console.error("OAuth logout failed", reason); - }); - } + onLogoutClick() { + OAuth2Client.logout( + oauth2LogoutOptions, + this.accessToken, // only used on android + ) + .then(() => { + // do something + }) + .catch(reason => { + console.error('OAuth logout failed', reason); + }); + } } ``` @@ -175,6 +180,7 @@ export class SignupComponent { See the `oauth2Options` and `oauth2RefreshOptions` interfaces at https://github.com/moberwasserlechner/capacitor-oauth2/blob/main/src/definitions.ts for details. Example: + ``` { authorizationBaseUrl: "https://accounts.google.com/o/oauth2/auth", @@ -200,8 +206,7 @@ Example: redirectUrl: "com.companyname.appname:/" // Bundle ID from google dev console } } - ``` - +``` #### authenticate() and logout() @@ -209,80 +214,79 @@ Example: These parameters are overrideable in every platform -| parameter | default | required | description | since | -|---------------------- |--------- |---------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |------- | -| appId | | yes | aka clientId, serviceId, ... | | -| authorizationBaseUrl | | yes | | | -| responseType | | yes | | | -| redirectUrl | | yes | | 2.0.0 | -| accessTokenEndpoint | | | If empty the authorization response incl code is returned. Known issue: Not on iOS! | | -| resourceUrl | | | 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 ``. | | -| additionalResourceHeaders | | | Additional headers for the resource request | 3.0.0 | -| pkceEnabled | `false` | | Enable PKCE if you need it. Note: On iOS because of #111 boolean values are not overwritten. You have to explicitly define the param in the subsection. | | -| logsEnabled | `false` | | Enable extensive logging. All plugin outputs are prefixed with `I/Capacitor/OAuth2ClientPlugin: ` across all platforms. Note: On iOS because of #111 boolean values are not overwritten. You have to explicitly define the param in the subsection. | 3.0.0 | -| scope | | | | | -| state | | | The plugin always uses a state.
If you don't provide one we generate it. | | -| additionalParameters | | | Additional parameters for anything you might miss, like `none`, `response_mode`.

Just create a key value pair.
```{ "key1": "value", "key2": "value, "response_mode": "value"}``` | | +| parameter | default | required | description | since | +| ------------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| appId | | yes | aka clientId, serviceId, ... | | +| authorizationBaseUrl | | yes | | | +| responseType | | yes | | | +| redirectUrl | | yes | | 2.0.0 | +| accessTokenEndpoint | | | If empty the authorization response incl code is returned. Known issue: Not on iOS! | | +| resourceUrl | | | 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 ``. | | +| additionalResourceHeaders | | | Additional headers for the resource request | 3.0.0 | +| pkceEnabled | `false` | | Enable PKCE if you need it. Note: On iOS because of #111 boolean values are not overwritten. You have to explicitly define the param in the subsection. | | +| logsEnabled | `false` | | Enable extensive logging. All plugin outputs are prefixed with `I/Capacitor/OAuth2ClientPlugin: ` across all platforms. Note: On iOS because of #111 boolean values are not overwritten. You have to explicitly define the param in the subsection. | 3.0.0 | +| scope | | | | | +| state | | | The plugin always uses a state.
If you don't provide one we generate it. | | +| additionalParameters | | | Additional parameters for anything you might miss, like `none`, `response_mode`.

Just create a key value pair.
`{ "key1": "value", "key2": "value, "response_mode": "value"}` | | **Platform Web** -| parameter | default | required | description | since | -|--------------- |--------- |---------- |---------------------------------------- |------- | -| windowOptions | | | e.g. width=500,height=600,left=0,top=0 | | -| windowTarget | `_blank` | | | | -| windowReplace | | | | 3.0.0 | +| parameter | default | required | description | since | +| ------------- | -------- | -------- | -------------------------------------- | ----- | +| windowOptions | | | e.g. width=500,height=600,left=0,top=0 | | +| windowTarget | `_blank` | | | | +| windowReplace | | | | 3.0.0 | **Platform Android** -| parameter | default | required | description | since | -|------------------------------ |--------- |---------- |-------------------------------------------------------------------------------------------------------------------------- |------- | -| customHandlerClass | | | Provide a class name implementing `com.getcapacitor.community.genericoauth2.handler.OAuth2CustomHandler` | | -| handleResultOnNewIntent | `false` | | Alternative to handle the activity result. The `onNewIntent` method is only call if the App was killed while logging in. | | -| handleResultOnActivityResult | `true` | | | | +| parameter | default | required | description | since | +| ---------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------ | ----- | +| customHandlerClass | | | Provide a class name implementing `com.getcapacitor.community.genericoauth2.handler.OAuth2CustomHandler` | | +| handleResultOnNewIntent | `false` | | Alternative to handle the activity result. The `onNewIntent` method is only call if the App was killed while logging in. | | +| handleResultOnActivityResult | `true` | | | | **Platform iOS** -| parameter | default | required | description | since | -|-------------------- |--------- |---------- |------------------------------------------------------------------------------------------------ |------- | -| customHandlerClass | | | Provide a class name implementing `CapacitorCommunityGenericOauth2.OAuth2CustomHandler` | | -| siwaUseScope | | | SiWA default scope is `name email` if you want to use the configured one set this param `true` | 2.1.0 | - +| parameter | default | required | description | since | +| ------------------ | ------- | -------- | ---------------------------------------------------------------------------------------------- | ----- | +| customHandlerClass | | | Provide a class name implementing `CapacitorCommunityGenericOauth2.OAuth2CustomHandler` | | +| siwaUseScope | | | SiWA default scope is `name email` if you want to use the configured one set this param `true` | 2.1.0 | #### refreshToken() -| parameter | default | required | description | since | -|--------------------- |--------- |---------- |------------------------------ |------- | -| appId | | yes | aka clientId, serviceId, ... | | -| accessTokenEndpoint | | yes | | | -| refreshToken | | yes | | | -| scope | | | | | +| parameter | default | required | description | since | +| ------------------- | ------- | -------- | ---------------------------- | ----- | +| appId | | yes | aka clientId, serviceId, ... | | +| accessTokenEndpoint | | yes | | | +| refreshToken | | yes | | | +| scope | | | | | ### Error Codes #### authenticate() -* ERR_PARAM_NO_APP_ID ... The appId / clientId is missing. (web, android, ios) -* ERR_PARAM_NO_AUTHORIZATION_BASE_URL ... The authorization base url is missing. (web, android, ios) -* ERR_PARAM_NO_RESPONSE_TYPE ... The response type is missing. (web, android, ios) -* ERR_PARAM_NO_REDIRECT_URL ... The redirect url is missing. (web, android, ios) -* 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) -* ERR_AUTHORIZATION_FAILED ... The authorization failed. -* ERR_NO_ACCESS_TOKEN ... No access_token found. (web, android) -* ERR_NO_AUTHORIZATION_CODE ... No authorization code was returned in the redirect response. (web, android, ios) -* USER_CANCELLED ... The user cancelled the login flow. (web, android, ios) -* ERR_CUSTOM_HANDLER_LOGIN ... Login through custom handler class failed. See logs and check your code. (android, ios) -* ERR_CUSTOM_HANDLER_LOGOUT ... Logout through custom handler class failed. See logs and check your code. (android, ios) -* ERR_ANDROID_NO_BROWSER ... No suitable browser could be found! (Android) -* 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) -* ERR_GENERAL ... A unspecific error. Check the logs to see want exactly happened. (web, android, ios) +- ERR_PARAM_NO_APP_ID ... The appId / clientId is missing. (web, android, ios) +- ERR_PARAM_NO_AUTHORIZATION_BASE_URL ... The authorization base url is missing. (web, android, ios) +- ERR_PARAM_NO_RESPONSE_TYPE ... The response type is missing. (web, android, ios) +- ERR_PARAM_NO_REDIRECT_URL ... The redirect url is missing. (web, android, ios) +- 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) +- ERR_AUTHORIZATION_FAILED ... The authorization failed. +- ERR_NO_ACCESS_TOKEN ... No access_token found. (web, android) +- ERR_NO_AUTHORIZATION_CODE ... No authorization code was returned in the redirect response. (web, android, ios) +- USER_CANCELLED ... The user cancelled the login flow. (web, android, ios) +- ERR_CUSTOM_HANDLER_LOGIN ... Login through custom handler class failed. See logs and check your code. (android, ios) +- ERR_CUSTOM_HANDLER_LOGOUT ... Logout through custom handler class failed. See logs and check your code. (android, ios) +- ERR_ANDROID_NO_BROWSER ... No suitable browser could be found! (Android) +- 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) +- ERR_GENERAL ... A unspecific error. Check the logs to see want exactly happened. (web, android, ios) #### refreshToken() -* ERR_PARAM_NO_APP_ID ... The appId / clientId is missing. (android, ios) -* 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) -* ERR_PARAM_NO_REFRESH_TOKEN ... The refresh token is missing. (android, ios) -* ERR_NO_ACCESS_TOKEN ... No access_token found. (web, android) -* ERR_GENERAL ... A unspecific error. Check the logs to see want exactly happened. (android, ios) +- ERR_PARAM_NO_APP_ID ... The appId / clientId is missing. (android, ios) +- 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) +- ERR_PARAM_NO_REFRESH_TOKEN ... The refresh token is missing. (android, ios) +- ERR_NO_ACCESS_TOKEN ... No access_token found. (web, android) +- ERR_GENERAL ... A unspecific error. Check the logs to see want exactly happened. (android, ios) ## Platform: Web/PWA @@ -292,6 +296,7 @@ As there is no provider SDK used to accomplish OAuth, no additional javascript f impact using this plugin in a web application. ### Register plugin + On Web/PWA the plugin is registered **automatically** by Capacitor. ## Platform: Android @@ -299,6 +304,7 @@ On Web/PWA the plugin is registered **automatically** by Capacitor. Prerequisite: [Capacitor Android Docs](https://capacitor.ionicframework.com/docs/android/configuration) ### Register plugin + On Android the plugin is registered **automatically** by Capacitor. ### Android Default Config @@ -308,6 +314,7 @@ Skip this, if you use a `OAuth2CustomHandler`. See below. #### android/app/src/main/res/AndroidManifest.xml The `AndroidManifest.xml` in your Capacitor Android project already contains + ```xml @@ -318,13 +325,17 @@ The `AndroidManifest.xml` in your Capacitor Android project already contains ``` Find the following line in your `AndroidManifest.xml` + ```xml ``` + and change it to + ```xml ``` + Note: Actually any value for `android:host` will do. It does not has to be `oauth`. This will fix an issues within the oauth workflow when the application is shown twice. @@ -352,8 +363,8 @@ android.defaultConfig.manifestPlaceholders = [ **Troubleshooting** -1) If your `appAuthRedirectScheme` does not get recognized because you are using a library that replaces it -(e.g.: onesignal-cordova-plugin), you will have to add it to your `buildTypes` like the following: +1. If your `appAuthRedirectScheme` does not get recognized because you are using a library that replaces it + (e.g.: onesignal-cordova-plugin), you will have to add it to your `buildTypes` like the following: ```groovy android.buildTypes.debug.manifestPlaceholders = [ @@ -364,14 +375,13 @@ android.buildTypes.release.manifestPlaceholders = [ ] ``` -2) "ERR_ANDROID_RESULT_NULL": See [Issue #52](https://github.com/moberwasserlechner/capacitor-oauth2/issues/52#issuecomment-525715515) for details. -I 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. - -3) To prevent some logout issues on certain OAuth2 providers (like Salesforce for example), you should provide the `id_token` parameter on the `logout(...)` function. -This ensures that not only the cookies are deleted, but also the logout link is called from the OAuth2 provider. -Also, it uses the system browser that the plugin uses (and not the user's default browser) to call the logout URL. -This additionally ensures that the cookies are deleted in the correct browser. +2. "ERR_ANDROID_RESULT_NULL": See [Issue #52](https://github.com/moberwasserlechner/capacitor-oauth2/issues/52#issuecomment-525715515) for details. + I 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. +3. To prevent some logout issues on certain OAuth2 providers (like Salesforce for example), you should provide the `id_token` parameter on the `logout(...)` function. + This ensures that not only the cookies are deleted, but also the logout link is called from the OAuth2 provider. + Also, it uses the system browser that the plugin uses (and not the user's default browser) to call the logout URL. + This additionally ensures that the cookies are deleted in the correct browser. ### Custom OAuth Handler @@ -388,6 +398,7 @@ See a full working example below! ## Platform: iOS ### Register plugin + On iOS the plugin is registered **automatically** by Capacitor. ### iOS Default Config @@ -420,38 +431,36 @@ This class has to implement `CapacitorCommunityGenericOauth2.OAuth2CustomHandler See a full working example below! - ## Platform: Electron - No timeline. - ## Where to store access tokens? You can use the [capacitor-secure-storage](https://www.npmjs.com/package/capacitor-secure-storage-plugin) plugin for this. This plugin stores data in secure locations for natives devices. + - For Android, it will store data in a [`AndroidKeyStore`](https://developer.android.com/training/articles/keystore) and a [`SharedPreferences`](https://developer.android.com/reference/android/content/SharedPreferences). - For iOS, it will store data in a [`SwiftKeychainWrapper`](https://github.com/jrendel/SwiftKeychainWrapper). - ## List of Providers These 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. -| Name | Example (config,...) | Notes | -|-----------|------------------------|-------| -| Google | [see below](#google) | | -| Facebook | [see below](#facebook) | | -| Azure | [see below](#azure-active-directory--azure-ad-b2c)| | -| Apple | [see below](#apple) | ios only | - +| Name | Example (config,...) | Notes | +| -------- | -------------------------------------------------- | -------- | +| Google | [see below](#google) | | +| Facebook | [see below](#facebook) | | +| Azure | [see below](#azure-active-directory--azure-ad-b2c) | | +| Apple | [see below](#apple) | ios only | ## Examples ### Apple #### iOS 13+ + Minimum config ```typescript @@ -486,30 +495,29 @@ appleLogin() { As "Signin with Apple" is only supported since iOS 13 you should show the according button only in that case. In Angular do sth like + ```typescript -import {Component, OnInit} from '@angular/core'; -import {Device, DeviceInfo} from "@capacitor/device"; -import {OAuth2Client} from "@capacitor-community/generic-oauth"; +import { Component, OnInit } from '@angular/core'; +import { Device, DeviceInfo } from '@capacitor/device'; +import { OAuth2Client } from '@capacitor-community/generic-oauth'; @Component({ - templateUrl: './siwa.component.html' + templateUrl: './siwa.component.html', }) export class SiwaComponent implements OnInit { - ios: boolean; siwaSupported: boolean; deviceInfo: DeviceInfo; async ngOnInit() { - this.deviceInfo = await Device.getInfo(); - this.ios = this.deviceInfo.platform === "ios"; - if (this.ios) { - const majorVersion: number = +this.deviceInfo.osVersion.split(".")[0]; - this.siwaSupported = majorVersion >= 13; - } + this.deviceInfo = await Device.getInfo(); + this.ios = this.deviceInfo.platform === 'ios'; + if (this.ios) { + const majorVersion: number = +this.deviceInfo.osVersion.split('.')[0]; + this.siwaSupported = majorVersion >= 13; + } } } - ``` And show the button only if `siwaSupported` is `true`. @@ -549,31 +557,33 @@ They share the same core features and therefore the plugin should work either wa #### PWA ```typescript -import {OAuth2AuthenticateOptions, OAuth2Client} from "@capacitor-community/generic-oauth"; +import { + OAuth2AuthenticateOptions, + OAuth2Client, +} from '@capacitor-community/generic-oauth'; export class AuthService { - getAzureB2cOAuth2Options(): OAuth2AuthenticateOptions { return { - appId: environment.oauthAppId.azureBc2.appId, - authorizationBaseUrl: `https://login.microsoftonline.com/${environment.oauthAppId.azureBc2.tenantId}/oauth2/v2.0/authorize`, - scope: "https://graph.microsoft.com/User.Read", // See Azure Portal -> API permission - accessTokenEndpoint: `https://login.microsoftonline.com/${environment.oauthAppId.azureBc2.tenantId}/oauth2/v2.0/token`, - resourceUrl: "https://graph.microsoft.com/v1.0/me/", - responseType: "code", - pkceEnabled: true, - logsEnabled: true, - web: { - redirectUrl: environment.redirectUrl, - windowOptions: "height=600,left=0,top=0", - }, - android: { - redirectUrl: "msauth://{package-name}/{url-encoded-signature-hash}" // See Azure Portal -> Authentication -> Android Configuration "Redirect URI" - }, - ios: { - pkceEnabled: true, // workaround for bug #111 - redirectUrl: "msauth.{package-name}://auth" - } + appId: environment.oauthAppId.azureBc2.appId, + authorizationBaseUrl: `https://login.microsoftonline.com/${environment.oauthAppId.azureBc2.tenantId}/oauth2/v2.0/authorize`, + scope: 'https://graph.microsoft.com/User.Read', // See Azure Portal -> API permission + accessTokenEndpoint: `https://login.microsoftonline.com/${environment.oauthAppId.azureBc2.tenantId}/oauth2/v2.0/token`, + resourceUrl: 'https://graph.microsoft.com/v1.0/me/', + responseType: 'code', + pkceEnabled: true, + logsEnabled: true, + web: { + redirectUrl: environment.redirectUrl, + windowOptions: 'height=600,left=0,top=0', + }, + android: { + redirectUrl: 'msauth://{package-name}/{url-encoded-signature-hash}', // See Azure Portal -> Authentication -> Android Configuration "Redirect URI" + }, + ios: { + pkceEnabled: true, // workaround for bug #111 + redirectUrl: 'msauth.{package-name}://auth', + }, }; } } @@ -616,9 +626,11 @@ import {OAuth2Client} from "@capacitor-community/generic-oauth"; } } ``` + ##### Prior configs +
Other configs that works in prior versions @@ -704,6 +716,7 @@ If you have **multiple** identity providers **or** your logins always ends in a you have to create an additional Activity in `AndroidManifest.xml`. These are both activities! Make sure to replace `com.company.project.MainActivity` with your real qualified class path! + ```xml Your Project's Name/string> com.company.project @@ -774,10 +788,11 @@ Open `Info.plist` in XCode by clicking right on that file -> Open as -> Source C **Important:** -* Do not enter `://` as part of your redirect url -* Make sure the `msauth.` prefix is present +- Do not enter `://` as part of your redirect url +- Make sure the `msauth.` prefix is present #### Troubleshooting + In case of problems please read [#91](https://github.com/moberwasserlechner/capacitor-oauth2/issues/91) and [#96](https://github.com/moberwasserlechner/capacitor-oauth2/issues/96) @@ -786,6 +801,7 @@ See this [example repo](https://github.com/loonix/capacitor-oauth2-azure-example ### Google #### PWA + ```typescript import {OAuth2Client} from "@capacitor-community/generic-oauth"; @@ -864,9 +880,9 @@ facebookLogin() { Since October 2018 Strict Mode for Redirect Urls is always on. ->Use Strict Mode for Redirect URIs +> Use Strict Mode for Redirect URIs ->Only allow redirects that use the Facebook SDK or that exactly match the Valid OAuth Redirect URIs. Strongly recommended. +> Only allow redirects that use the Facebook SDK or that exactly match the Valid OAuth Redirect URIs. Strongly recommended. Before that it was able to use `fb:/authorize` in a Android or iOS app and get the accessToken. @@ -880,16 +896,16 @@ To address this problem I created a integration with custom code in your app `cu See https://developers.facebook.com/docs/facebook-login/android/ for more background on how to configure Facebook in your Android app. -1) Add `implementation 'com.facebook.android:facebook-login:4.36.0'` to `android/app/build.gradle` as dependency. +1. Add `implementation 'com.facebook.android:facebook-login:4.36.0'` to `android/app/build.gradle` as dependency. -2) Add to `string.xml` +2. Add to `string.xml` ```xml fb ``` -3) Add to `AndroidManifest.xml` +3. Add to `AndroidManifest.xml` ```xml @@ -908,16 +924,13 @@ See https://developers.facebook.com/docs/facebook-login/android/ for more backgr ``` -4) Create a custom handler class -```java +4. Create a custom handler class +```java package com.companyname.appname; import android.app.Activity; - -import com.getcapacitor.community.genericoauth2.handler.AccessTokenCallback; -import com.getcapacitor.community.genericoauth2.handler.OAuth2CustomHandler; import com.companyname.appname.MainActivity; import com.facebook.AccessToken; import com.facebook.FacebookCallback; @@ -927,39 +940,51 @@ import com.facebook.login.LoginBehavior; import com.facebook.login.LoginManager; import com.facebook.login.LoginResult; import com.getcapacitor.PluginCall; - +import com.getcapacitor.community.genericoauth2.handler.AccessTokenCallback; +import com.getcapacitor.community.genericoauth2.handler.OAuth2CustomHandler; import java.util.Collections; public class YourAndroidFacebookOAuth2Handler implements OAuth2CustomHandler { @Override - public void getAccessToken(Activity activity, PluginCall pluginCall, final AccessTokenCallback callback) { + public void getAccessToken( + Activity activity, + PluginCall pluginCall, + final AccessTokenCallback callback + ) { AccessToken accessToken = AccessToken.getCurrentAccessToken(); if (AccessToken.isCurrentAccessTokenActive()) { callback.onSuccess(accessToken.getToken()); } else { LoginManager l = LoginManager.getInstance(); - l.logInWithReadPermissions(activity, Collections.singletonList("public_profile")); + l.logInWithReadPermissions( + activity, + Collections.singletonList("public_profile") + ); l.setLoginBehavior(LoginBehavior.WEB_ONLY); l.setDefaultAudience(DefaultAudience.NONE); - LoginManager.getInstance().registerCallback(((MainActivity) activity).getCallbackManager(), new FacebookCallback() { - @Override - public void onSuccess(LoginResult loginResult) { - callback.onSuccess(loginResult.getAccessToken().getToken()); - } + LoginManager + .getInstance() + .registerCallback( + ((MainActivity) activity).getCallbackManager(), + new FacebookCallback() { + @Override + public void onSuccess(LoginResult loginResult) { + callback.onSuccess(loginResult.getAccessToken().getToken()); + } - @Override - public void onCancel() { - callback.onCancel(); - } + @Override + public void onCancel() { + callback.onCancel(); + } - @Override - public void onError(FacebookException error) { - callback.onCancel(); - } - }); + @Override + public void onError(FacebookException error) { + callback.onCancel(); + } + } + ); } - } @Override @@ -970,7 +995,8 @@ public class YourAndroidFacebookOAuth2Handler implements OAuth2CustomHandler { } ``` -5) Change your MainActivity like + +5. Change your MainActivity like ```java public class MainActivity extends BridgeActivity { @@ -986,7 +1012,11 @@ public class MainActivity extends BridgeActivity { } @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { + protected void onActivityResult( + int requestCode, + int resultCode, + Intent data + ) { super.onActivityResult(requestCode, resultCode, data); if (callbackManager.onActivityResult(requestCode, resultCode, data)) { return; @@ -996,15 +1026,15 @@ public class MainActivity extends BridgeActivity { public CallbackManager getCallbackManager() { return callbackManager; } - } + ``` **iOS** See https://developers.facebook.com/docs/swift/getting-started and https://developers.facebook.com/docs/swift/login -1) Add Facebook pods to `ios/App/Podfile` and run `pod install` afterwards +1. Add Facebook pods to `ios/App/Podfile` and run `pod install` afterwards ``` platform :ios, '13.0' @@ -1035,7 +1065,7 @@ target 'App' do end ``` -2) Add some Facebook configs to your `Info.plist` +2. Add some Facebook configs to your `Info.plist` ```xml CFBundleURLTypes @@ -1060,7 +1090,7 @@ end ``` -3) Create a custom handler class +3. Create a custom handler class ```swift import Foundation @@ -1106,8 +1136,8 @@ import CapacitorCommunityGenericOauth2 This handler will be automatically discovered up by the plugin and handles the login using the Facebook SDK. See https://developers.facebook.com/docs/swift/login/#custom-login-button for details. -4) The users that have redirect problem after success grant add the following code to `ios/App/App/AppDelegate.swift`. -This code correctly delegate the FB redirect url to be managed by Facebook SDK. +4. The users that have redirect problem after success grant add the following code to `ios/App/App/AppDelegate.swift`. + This code correctly delegate the FB redirect url to be managed by Facebook SDK. ```swift import UIKit @@ -1145,6 +1175,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { See [Contribution Guidelines](https://github.com/moberwasserlechner/capacitor-oauth2/blob/main/.github/CONTRIBUTING.md). ## Changelog + See [CHANGELOG](https://github.com/moberwasserlechner/capacitor-oauth2/blob/main/CHANGELOG.md). ## License