UNPKG

api-console-assets

Version:

This repo only exists to publish api console components to npm

990 lines (930 loc) 36.6 kB
<!-- @license Copyright 2016 The Advanced REST client authors <arc@mulesoft.com> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../paper-masked-input/paper-masked-input.html"> <link rel="import" href="../paper-icon-button/paper-icon-button.html"> <link rel="import" href="../paper-button/paper-button.html"> <link rel="import" href="../paper-input/paper-input.html"> <link rel="import" href="../arc-icons/arc-icons.html"> <link rel="import" href="../iron-icon/iron-icon.html"> <link rel="import" href="../paper-styles/paper-styles.html"> <link rel="import" href="../iron-flex-layout/iron-flex-layout.html"> <link rel="import" href="../iron-form/iron-form.html"> <link rel="import" href="../paper-item/paper-item.html"> <link rel="import" href="../paper-toast/paper-toast.html"> <link rel="import" href="../paper-dropdown-menu/paper-dropdown-menu.html"> <link rel="import" href="../paper-listbox/paper-listbox.html"> <link rel="import" href="../oauth2-scope-selector/oauth2-scope-selector.html"> <link rel="import" href="../paper-spinner/paper-spinner.html"> <link rel="import" href="../iron-collapse/iron-collapse.html"> <link rel="import" href="../paper-ripple/paper-ripple.html"> <link rel="import" href="../paper-tooltip/paper-tooltip.html"> <link rel="import" href="../paper-checkbox/paper-checkbox.html"> <link rel="import" href="../clipboard-copy/clipboard-copy.html"> <link rel="import" href="../arc-polyfills/arc-polyfills.html"> <link rel="import" href="auth-methods-behavior.html"> <!-- The `<auth-method-oauth2>` element displays a form to provide the OAuth 2.0 settings. ### Example ``` <auth-method-oauth2></auth-method-oauth2> ``` This element uses `oauth2-scope-selector` so the `allowedScopes`, `preventCustomScopes` and `scopes` properties will be set on this element. See documentation of `oauth2-scope-selector` for more description. ### Forcing the user to select scope from the list ``` <auth-method-oauth2 prevent-custom-scopes></auth-method-oauth2> ``` ``` var form = document.querySelector('auth-method-oauth2'); form.allowedScopes = ['profile', 'email']; ``` ## Authorizing the user The element sends the `oauth2-token-requested` with the OAuth settings provided with the form. Any element / app can handle this event and perform authorization. When the authorization is performed the app / other element should set back `tokenValue` property of this element or send the `oauth2-token-response` with token response value so the change will can reflected in the UI. ARC provides the `oauth2-authorization` element that can handle this events. ### Example ``` <auth-method-oauth2></auth-method-oauth2> <oauth2-authorization></oauth2-authorization> ``` The `oauth2-authorization` can be set anywhere in the DOM up from this element siblings to the body. See demo for example usage. ## Redirect URL Most OAuth 2 providers requires setting the redirect URL with the request. This can't be changed by the user and redirect URL can be only set in the provider's settings panel. The element accepts the `redirectUrl` property which will be displayed to the user that (s)he has to set up this callback URL in the OAuth provider settings. It can be any URL where token / code will be handled properly and the value returned to the `oauth2-authorization` element. See `oauth2-authorization` documentation for more information. If you going to use `oauth2-authorization` popup then the redirect URL value must be set to: `/bower_components/oauth-authorization/oauth-popup.html`. Mind missing `2` in `oauth-authorization`. This popup is a common popup for auth methods. ### Styling `<auth-methods>` provides the following custom properties and mixins for styling: Custom property | Description | Default ----------------|-------------|---------- `--auth-method-oauth2` | Mixin applied to the element. | `{}` `--auth-method-panel` | Mixin applied to all auth elements. | `{}` ### Theming Use this mixins as a theming option across all ARC elements. Custom property | Description | Default ----------------|-------------|---------- `--icon-button` | Mixin applied to `paper-icon-buttons`. | `{}` `--icon-button-hover` | Mixin applied to `paper-icon-buttons` when hovered. | `{}` `--input-line-color` | Mixin applied to the input underline | `{}` `--form-label` | Mixin applied to form labels. It will not affect `paper-*` labels | `{}` `--auth-button` | Mixin applied to authorization and next buttons` | `{}` `--auth-button-hover` | Mixin for :hover state for authorization and next buttons` | `{}` `--auth-button-disabled` | Mixin for disabled state for authorization and next buttons` | `{}` @group UI Elements @element auth-method-oauth2 @demo demo/oauth2.html --> <dom-module id="auth-method-oauth2"> <template strip-whitespace> <style include="auth-methods-styles"> :host { display: block; @apply(--auth-method-panel); @apply(--auth-method-oauth2); --paper-icon-button: { color: var(--hint-trigger-color, rgba(0, 0, 0, 0.54)); transition: color 0.25s linear; @apply(--icon-button); } --paper-icon-button-hover: { color: var(--hint-trigger-hover-color, rgba(0, 0, 0, 0.78)); @apply(--icon-button-hover); } } .form { @apply(--layout-flex); max-width: 700px; } oauth2-scope-selector { margin: 24px 0; outline: none; } .grant-dropdown { width: 320px; @apply(--auth-grant-dropdown); } .auth-button { color: var(--accent-color); background-color: #fff; @apply(--auth-button); } .auth-button:hover { @apply(--auth-button-hover); } .auth-button[disabled] { background-color: rgba(0, 0, 0, 0.24); color: rgba(0, 0, 0, 0.54); @apply(--auth-button-disabled); } .authorize-actions { margin-top: 12px; } .read-only-param-field { background-color: rgba(0, 0, 0, 0.12); @apply(--arc-font-body1); display: block; white-space: pre-wrap; word-wrap: break-word; word-break: break-all; @apply(--layout-horizontal); } .read-only-param-field.padding { padding: 12px; } .read-only-param-field.no-background { background-color: transparent; } label { @apply(--form-label); } .token-info, .redirect-info { @apply(--arc-font-body1); font-weight: 200; color: rgba(0, 0, 0, 0.54); } .code { font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace; -webkit-font-smoothing: antialiased; @apply(--arc-font-code1); @apply(--layout-flex); } .token-label { font-weight: 500; font-size: 16px; } .current-token { margin-top: 24px; padding: 12px; border: 2px #3D8099 solid; } .current-token, .redirect-section, oauth2-scope-selector { max-width: 560px; width: calc(100% - 16px); box-sizing: border-box; } .redirect-section { @apply(--auth-redirect-section); } *[hiddable] { display: none; } *[data-grant="authorization_code"] *[data-visible~="authorization_code"], *[data-grant="client_credentials"] *[data-visible~="client_credentials"], *[data-grant="implicit"] *[data-visible~="implicit"], *[data-grant="password"] *[data-visible~="password"] { display: block; } </style> <form is="iron-form" id="form" data-grant$="[[grantType]]"> <div class="row" hidden$="[[noGrantType]]"> <div class$="[[_computeStepperClass(isSelectedType)]]" on-tap="_clearTypeSelection"> <span class="step">[[_computeStep(stepStartIndex, 1)]]</span> <span class="step-header"> <span class="step-title"> Select OAuth 2.0 grant type <iron-icon icon="arc:edit" class="edit-icon" title="Click to make changes"></iron-icon> </span> <span class="step-selection" hidden$="[[!isSelectedType]]">[[_computeSelectedTypeLabel(grantType)]]</span> </span> <paper-ripple></paper-ripple> </div> <div class="step-content"> <div class="line"></div> <iron-collapse opened="[[typeSelectorOpened]]" class="content"> <div class="content"> <paper-dropdown-menu label="Grant type" class="grant-dropdown" required auto-validate> <paper-listbox class="dropdown-content" selected="{{grantType}}" attr-for-selected="data-type"> <template is="dom-repeat" items="[[grantTypes]]"> <paper-item data-type$="[[item.type]]">[[item.label]]</paper-item> </template> </paper-listbox> </paper-dropdown-menu> </div> </iron-collapse> </div> </div> <div class="row"> <div class="stepper"> <span class="step">[[_computeStep(stepStartIndex, 2)]]</span> <span class="step-header"> <span class="step-title">Set authorization data</span> </span> </div> <div class="step-content" id="authDataForm"> <div class="line"></div> <div class="content"> <paper-masked-input auto-validate required label="Client id" value="{{clientId}}" id="clientId" autocomplete="on"></paper-masked-input> <paper-tooltip for="clientId" position="bottom">Your client ID registered in your OAuth provider.</paper-tooltip> <paper-masked-input auto-validate required label="Client secret" value="{{clientSecret}}" id="clientSecret" hiddable data-visible="client_credentials authorization_code" disabled$="[[_isFieldHidden(grantType, 'client_credentials', 'authorization_code')]]" autocomplete="on"></paper-masked-input> <paper-tooltip for="clientSecret" position="bottom">The client secret is generated by your provider unique string for your app. Check provider's console to get the code.</paper-tooltip> <template is="dom-if" if="[[isAdvanced]]"> <paper-checkbox class="adv-settings-input" checked="{{advancedOpened}}">Advanced settings</paper-checkbox> </template> <iron-collapse opened="[[advancedOpened]]"> <paper-input auto-validate required label="Authorization url" value="{{authUrl}}" id="authUrl" hiddable data-visible="implicit authorization_code" disabled$="[[_isFieldHidden(grantType, 'implicit', 'authorization_code')]]" type="text" autocomplete="on"> <paper-icon-button suffix on-tap="_clearField" icon="arc:clear" alt="Clear input icon" title="Clear input"></paper-icon-button> </paper-input> <paper-tooltip for="authUrl" position="bottom">The authorization URL initializes the OAuth flow. If you don't know the authorization URL check your provider's documentation.</paper-tooltip> <paper-input auto-validate required label="Access token URL" value="{{accessTokenUrl}}" id="accessTokenUrl" hiddable data-visible="client_credentials authorization_code password" disabled$="[[_isFieldHidden(grantType, 'client_credentials', 'authorization_code', 'password')]]" type="text" autocomplete="on"> <paper-icon-button suffix on-tap="_clearField" icon="arc:clear" alt="Clear input icon" title="Clear input"></paper-icon-button> </paper-input> <paper-tooltip for="accessTokenUrl" position="bottom">The access token URL is used by server implementations to exchange access code for access token.</paper-tooltip> <paper-masked-input auto-validate required label="Username" value="{{username}}" id="username" hiddable data-visible="password" disabled$="[[_isFieldHidden(grantType, 'password')]]" autocomplete="on"></paper-masked-input> <paper-tooltip for="username" position="bottom">The username required for this OAuth authentication.</paper-tooltip> <paper-masked-input auto-validate required label="Password" value="{{password}}" id="password" hiddable data-visible="password" disabled$="[[_isFieldHidden(grantType, 'password')]]" autocomplete="on"></paper-masked-input> <paper-tooltip for="password" position="bottom">The password required for this OAuth authentication.</paper-tooltip> <div hiddable data-visible="implicit authorization_code"> <oauth2-scope-selector allowed-scopes="[[allowedScopes]]" prevent-custom-scopes="[[preventCustomScopes]]" scopes="{{scopes}}" disabled$="[[_isFieldHidden(grantType, 'implicit', 'authorization_code')]]"></oauth2-scope-selector> </div> </iron-collapse> </div> </div> </div> <div class="row"> <div class="stepper"> <span class="step">[[_computeStep(stepStartIndex, 3)]]</span> <span class="step-header"> <span class="step-title">Set redirect URL</span> </span> </div> <div class="step-content"> <div class="line"></div> <div class="content"> <div class="redirect-section"> <p class="redirect-info">Set this redirect URL in OAuth 2.0 provider settings.</p> <p class="read-only-param-field padding"> <span class="code" tabindex="0" id="redirectLabel">[[redirectUrl]]</span> <paper-icon-button icon="arc:content-copy" on-tap="_copyContent" data-src="redirect" id="redirectCopyButton"></paper-icon-button> </p> </div> <div class="authorize-actions" hidden$="[[hasTokenValue]]"> <paper-button disabled$="[[_authorizing]]" class="auth-button" on-tap="authorize">Get access token</paper-button> <paper-spinner active="[[_authorizing]]"></paper-spinner> </div> <div class="current-token" hidden$="[[!hasTokenValue]]"> <label class="token-label">Current token</label> <p class="token-info">The token will be set to the corresponding field (header or query parameter).</p> <p class="read-only-param-field no-background"> <span class="code" tabindex="0" id="tokenLabel">[[tokenValue]]</span> <paper-icon-button icon="arc:content-copy" on-tap="_copyContent" data-src="token" id="tokenCopyButton"></paper-icon-button> </p> <div class="authorize-actions"> <paper-button disabled$="[[_authorizing]]" class="auth-button" on-tap="authorize">Refresh access token</paper-button> <paper-spinner active="[[_authorizing]]"></paper-spinner> </div> </div> </div> </div> </div> </form> <paper-toast text="" duration="5000"></paper-toast> <clipboard-copy></clipboard-copy> </template> <script> Polymer({ is: 'auth-method-oauth2', behaviors: [ArcBehaviors.AuthMethodsBehavior], /** * Fired when user requested to perform an authorization. * The details object vary depends on the `grantType` property. * However this event always fire two properties set on the `detail` object: `type` and * `clientId`. * * @event oauth2-token-requested * @param {String} type The type of grant option selected by the user. `implicit` is * the browser flow where token ir requested. `authorization_code` or server flow is where * client asks for the authorization code and exchange it later for the auth token using * client secret. Other options are `password` and `client_credentials`. * @param {String} clientId Every type requires `clientId`. * @param {String} authorizationUrl Token authorization URL. Used in `implicit` and * `authorization_code` types. In both cases means the initial endpoint to request for token * or the authorization code. * @param {Array<String>} scopes A list of scopes seleted by the user. Used in `implicit` * and `authorization_code` types. * @param {String} redirectUrl A redirect URL of the client after authorization (or error). * This must be set in the provider's OAuth settings. Callback URL must communicate with * the app to pass the information back to the application. User can't change the `redirectUrl` * but the app shouldn't rely on this value since in browser environment it is possible to * temper with variables. The `redirectUrl` must be set to this element by owner app (which * must know this value). A `redirectUrl` is set for `implicit` and `authorization_code` * types. * @param {String} clientSecret The client secret that user can get from the OAuth provider * settings console. User in `authorization_code` and `client_credentials` types. * @param {String} accessTokenUrl An URL to exchange code for the access token. Used by * `authorization_code`, `client_credentials` and `password` types. * @param {String} username Used with `password` type. * @param {String} password Used with `password` type. */ /** * Fired when the any of the auth method settings has changed. * This event will be fired quite frequently - each time anything in the text field changed. * With one exception. This event will not be fired if the validation of the form didn't passed. * * This event will set current settings as a detail object which are the same as for the * `oauth2-token-requested` event. Additionally it will contain a `tokenValue` property. This * valye can be `undefined` if token hasn't been requested yet by the user. * Clients should support a situaltion when the user do not request the token before requesting * the resource and perform authorization. * * @event auth-settings-changed * @param {Object} settings See the `oauth2-token-requested` for detailed * description * @param {String} type The authentication type selected by the user. * @param {Boolean} valid True if the form has been validated. */ /** * Fired when the request token has been obtained and it's ready to serve. * Because only one auth panel can be displayed ad a time it can be assumed * that if new token has been obtained then it is current authorization * method. * * @event oauth2-token-ready * @param {String} token The OAuth 2.0 token */ properties: { // Seleted authorization grand type. grantType: { type: String, value: '', notify: true }, // Computed value, true if the `grantType` is set. isSelectedType: { type: Boolean, value: false, computed: '_computeIsSelectedType(grantType)' }, /** * If true, OAuth flow selector will be collapsed. */ forceHideTypeSelector: { type: Boolean, value: false }, // Computed value, true if the type selector is allowd to be hidden typeSelectorOpened: { type: Boolean, value: false, // jscs:disable maximumLineLength computed: '_computeTypeSelectorOpened(isSelectedType, forceHideTypeSelector, _typeSelectorForceOpened)' // jscs:enable maximumLineLength }, // The client ID for the auth token. clientId: { type: String, notify: true, value: '' }, // The client secret. It to be used when selected server flow. clientSecret: { type: String, notify: true, value: '' }, // The authorization URL to initialize the OAuth flow. authUrl: { type: String, notify: true, value: '' }, // The access token URL to exchange code for token. It is used in server flow. accessTokenUrl: { type: String, notify: true, value: '' }, // The password. To be used with the password flow. password: { type: String, notify: true, value: '' }, // The password. To be used with the password flow. username: { type: String, notify: true, value: '' }, /** * A callback URL to be used with this element. * User can't change the callback URL and it will inform the user to setup OAuth to use * this value. * * This is relevant when selected flow is the browser flow. */ redirectUrl: String, /** * List of user selected scopes. * It can be pre-populated with list of scopes (array of strings). */ scopes: Array, /** * List of pre-defined scopes to choose from. It will be passed to the `oauth2-scope-selector` * element. */ allowedScopes: Array, /** * If true then the `oauth2-scope-selector` will disallow to add a scope that is not * in the `allowedScopes` list. Has no effect if the `allowedScopes` is not set. */ preventCustomScopes: Boolean, // True when currently authorizing the user. _authorizing: Boolean, /** * When the user authorized the app it should be set to the token value. * This element do not perform authorization. Other elements must intercept * `oauth2-token-requested` and perform the authorization. As a result the element * performing an authorization should set back the auth token on the event target object * (this element). */ tokenValue: { type: String, observer: '_tokenValueChanged', value: '' }, // Computed value, true if access token is set. hasTokenValue: { type: Boolean, value: false, readOnly: true }, /** * RAML `securedBy` obejct definition. * If set, it will prefill the settings in the auth panel. */ ramlSettings: Object, // List of all possible grant types; _supportedGrantTypes: { type: Array, value: function() { return [{ type: 'implicit', label: 'Access token (browser flow)' }, { type: 'authorization_code', label: 'Authorization code (server flow)' }, { type: 'client_credentials', label: 'Client credentials' }, { type: 'password', label: 'Password' }]; } }, // Currently available grant types. grantTypes: { type: Array }, // Tru whem the element has been initialized. _initialized: Boolean, // If true, the flow type selector will be forced to be opened _typeSelectorForceOpened: { type: Boolean, value: false }, /** * The element will automatically hide following fileds it the element has been initialized * with values for this fields (without user interaction): * * - autorization url * - token url * - scopes * * If all this values are set then the element will set `isAdvanced` attribute and set * `advancedOpened` to false * * Setting this property will prevent this behavior. */ noAuto: Boolean, /** * If set it will render autorization url, token url and scopes as advanced options * activated on user interaction. */ isAdvanced: Boolean, /** * If true then the advanced options are opened. */ advancedOpened: Boolean, /** * If set, the grant typr selector will be hidden from the UI. */ noGrantType: { type: Boolean, observer: '_noGrantTypeChanged' } }, observers: [ // jscs:disable maximumLineLength '_settingsChanged(grantType, clientId, clientSecret, authUrl, accessTokenUrl, password, username, scopes.*, tokenValue, _initialized)', // jscs:enable maximumLineLength '_ramlSettingsChanged(ramlSettings.*)', '_updateStepperState(noStepper)' ], ready: function() { this._initialized = true; this._autoHide(); }, _attachListeners: function(node) { this.listen(node, 'oauth2-error', '_oauth2ErrorHandler'); this.listen(node, 'oauth2-token-response', '_oauth2SccessHandler'); this.listen(node, 'request-header-changed', '_headerChangedHandler'); this._updateGrantTypes(); }, _detachListeners: function(node) { this.unlisten(node, 'oauth2-error', '_oauth2ErrorHandler'); this.unlisten(node, 'oauth2-token-response', '_oauth2SccessHandler'); this.unlisten(node, 'request-header-changed', '_headerChangedHandler'); }, /** * This function hides all non-crucial fields that has been pre-filled when element has been * initialize (values not provided by the user). Hidden fields will be available under * "advanced" options. * * To prevent this behavior set `no-auto` attribute on this element. */ _autoHide: function() { if (this.noAuto) { this.advancedOpened = true; return; } if (!!this.authUrl && !!this.accessTokenUrl && !!(this.scopes && this.scopes.length)) { this.isAdvanced = true; this.advancedOpened = false; } else { this.advancedOpened = true; } }, /** * Gets a map of current settings (user provided data). */ get settings() { return this._getSettings(); }, /** * Validate the form. * * @param {Boolean} passive If true then it will check validity of the form but will not * highlight the fields when invalid. Default to false. * @return {Boolean} `true` if valid, `false` otherwise. */ validate: function(passive) { return passive ? this.$.form.checkValidity() : this.$.form.validate(); }, _settingsChanged: function() { var validationResult = this.$.form.validate(); var settings = this._getSettings(); var detail = { settings: settings, type: 'oauth2', valid: validationResult }; this.fire('auth-settings-changed', detail); }, // Removes a value from the (paper-)input going up through path of the event. _clearField: function(e) { e = Polymer.dom(e); var path = e.path; var inputTarget; while ((inputTarget = path.shift())) { if (inputTarget.nodeName === 'INPUT' || inputTarget.nodeName === 'PAPER-INPUT') { break; } } if (!inputTarget) { return; } inputTarget.value = ''; }, // Checks if the HTML element should be visible in the UI for given properties. _isFieldHidden: function() { var args = Array.from(arguments); var grantType = args.splice(0, 1)[0]; return args.indexOf(grantType) === -1; }, // Handler for "authorize" button click. Sends the `oauth2-token-requested` event. authorize: function() { var validationResult = this.$.form.validate(); if (!validationResult) { return; } var detail = this._getSettings(); this._lastState = this.generateState(); detail.state = this._lastState; this._authorizing = true; this.fire('oauth2-token-requested', detail); }, /** * Generates `state` parameter for the OAuth2 call. * * @return {String} Generated state string. */ generateState: function() { var text = ''; var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; for (var i = 0; i < 6; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; }, /** * Returns current configuration of the OAuth2. * * @return {Object} Current OAuth2 configuration. */ _getSettings: function() { var detail = { type: this.grantType, clientId: this.clientId, tokenValue: this.tokenValue || '' }; switch (this.grantType) { case 'implicit': // The browser flow. detail.authorizationUrl = this.authUrl; detail.redirectUrl = this.redirectUrl; detail.scopes = this.scopes; break; case 'authorization_code': // The server flow. detail.authorizationUrl = this.authUrl; detail.clientSecret = this.clientSecret; detail.accessTokenUrl = this.accessTokenUrl; detail.redirectUrl = this.redirectUrl; detail.scopes = this.scopes; break; case 'client_credentials': // The server flow. detail.clientSecret = this.clientSecret; detail.accessTokenUrl = this.accessTokenUrl; break; case 'password': // The server flow. detail.username = this.username; detail.password = this.password; detail.accessTokenUrl = this.accessTokenUrl; break; } return detail; }, // Handler for the OAuth token value change. Enables the method if not active. _tokenValueChanged: function(newValue) { this._authorizing = false; if (newValue) { this._setHasTokenValue(true); } else { this._setHasTokenValue(false); } }, _oauth2ErrorHandler: function(e) { var info = e.detail; // API console may not support state check (mey not return it back) if (typeof info.state !== 'undefined') { if (info.state !== this._lastState) { return; } } this._authorizing = false; this._lastState = undefined; var toast = this.$$('paper-toast'); toast.text = info.message; toast.opened = true; }, _oauth2SccessHandler: function(e) { var info = e.detail; // API console may not support state check (mey not return it back) if (typeof info.state !== 'undefined') { if (info.state !== this._lastState) { return; } } this._lastState = undefined; if (info.accessToken && info.accessToken !== this.tokenValue) { this.set('tokenValue', info.accessToken); this.fire('oauth2-token-ready', { token: info.accessToken }); } }, _ramlSettingsChanged: function(record) { if (!record || !record.base) { return; } var type = record.base; if (!type || !type.settings) { return; } this.preFill(type.settings); this._autoHide(); }, preFill: function(settings) { if (!settings) { throw new Error('The `settings` argument is not set.'); } var grants = settings.authorizationGrants; if (typeof grants === 'string') { grants = [grants]; } if (grants && grants instanceof Array && grants.length) { var index = grants.indexOf('code'); if (index !== -1) { grants[index] = 'authorization_code'; } this._updateGrantTypes(grants); } else { this._updateGrantTypes(); } if (settings.accessTokenUri) { this.accessTokenUrl = settings.accessTokenUri; } if (settings.authorizationUri) { this.authUrl = settings.authorizationUri; } if (settings.scopes) { this.scopes = settings.scopes; } }, /** * Updates list of OAuth grant types supported by current endpoint. * The information should be available in RAML file. * * @param {Array<String>?} supportedTypes List of supported types. If empty * or not set then all available types will be displayed. */ _updateGrantTypes: function(supportedTypes) { var available = this._supportedGrantTypes.map(function(item) { return item; }); if (!supportedTypes || !supportedTypes.length) { this.set('grantTypes', available); return; } var i; for (i = available.length - 1; i >= 0; i--) { if (supportedTypes.indexOf(available[i].type) === -1) { available.splice(i, 1); } } this.set('grantTypes', available); // check if current selection is still available var current = this.grantType; var hasCurrent = false; if (current) { for (i = available.length - 1; i >= 0; i--) { if (available[i].type === current) { hasCurrent = true; break; } } } if (!hasCurrent) { if (available && available[0]) { this.set('grantType', available[0].type); } else { this.set('grantType', ''); } } }, // Computes boolean value if the `grantType` is set. _computeIsSelectedType: function(grantType) { return !!grantType; }, _computeStepperClass: function(isSelected) { var cls = 'stepper'; if (isSelected) { cls += ' active'; } return cls; }, _clearTypeSelection: function() { this.grantType = ''; }, _computeSelectedTypeLabel: function(grantType) { switch (grantType) { case 'implicit': return 'Access token (browser flow)'; case 'authorization_code': return 'Authorization code (server flow)'; case 'client_credentials': return 'Client credentials'; case 'password': return 'Password'; } }, _copyContent: function(e) { e = Polymer.dom(e); var src = e.localTarget.dataset.src; if (!src) { throw new Error('Copy to clipboard require the data-src attribute.'); } var params; switch (src) { case 'redirect': params = { text: this.$.redirectLabel.innerText, button: this.$.redirectCopyButton }; break; case 'token': params = { text: this.$.tokenLabel.innerText, button: this.$.tokenCopyButton }; break; default: throw new Error('Unknown src value'); } var elm = this.$$('clipboard-copy'); elm.content = params.text; if (elm.copy()) { params.button.icon = 'done'; } else { params.button.icon = 'error'; } setTimeout(this._resetCopyButtonState.bind(this, params.button), 1000); }, _resetCopyButtonState: function(button) { button.icon = 'content-copy'; }, _updateStepperState: function(noStepper) { this._typeSelectorForceOpened = noStepper ? true : false; // can be undefined }, _computeTypeSelectorOpened: function(isSelectedType, forceHideTypeSelector, _typeSelectorForceOpened) { if (forceHideTypeSelector) { return false; } if (_typeSelectorForceOpened || !isSelectedType) { return true; } return false; }, _noGrantTypeChanged: function(newValue, oldValue) { if (newValue) { this.stepStartIndex--; } else if (oldValue !== undefined) { this.stepStartIndex++; } }, /** * Handler for the `request-header-changed` custom event. * If the panel is opened the it checks if current header updates * authorization. */ _headerChangedHandler: function(e) { if (!this._isOpened || e.defaultPrevented) { return; } var name = e.detail.name; if (!name) { return; } name = name.toLowerCase(); if (name !== 'authorization') { return; } var value = e.detail.value; if (!value) { if (this.tokenValue) { this.set('tokenValue', ''); } return; } var lowerValue = value.toLowerCase(); if (lowerValue.indexOf('bearer') !== 0) { if (this.tokenValue) { this.set('tokenValue', ''); } return; } value = value.substr(7); this.set('tokenValue', value); } }); </script> </dom-module>