Skip to content

Instantly share code, notes, and snippets.

@Scarygami
Last active April 16, 2017 22:10
Show Gist options
  • Save Scarygami/7752c01b08a1c883e679 to your computer and use it in GitHub Desktop.
Save Scarygami/7752c01b08a1c883e679 to your computer and use it in GitHub Desktop.
Polymer Google Sign-in
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>google-signin Demo</title>
<script src="platform/platform.js"></script>
<link rel="import" href="google-signin/google-signin.html">
<link rel="import" href="google-calendar/google-calendar.html">
<!-- Demo only styles -->
<style>
@import url(http://fonts.googleapis.com/css?family=Roboto:400,100,100italic,300,300italic,400italic,500,700,500italic,900,700italic,900italic);
* { font-family: 'Roboto', sans-serif; line-height:1.2; vertical-align:middle; }
body {
background: rgba(204, 204, 204, 0.31);
}
.card {
min-width: 300px;
max-width: 400px;
padding:1.5rem;
box-shadow:0 1px 2px #aaa;
background:white;
margin:1rem 1rem 1rem;
border-radius:3px;
user-select:none;
transform-origin:top left;
position:relative;
z-index:2;
}
.card:nth-child(even){
transform-origin:top right;
}
.map {
background: whitesmoke;
margin: .5rem -1.5rem 0 -1.5rem;
padding: 0.5rem;
}
h1 {
font-size:2rem;
font-weight:200;
}
h1 strong {
font-weight:300;
color:#539D00;
}
h2 {
font-size:.9rem;
line-height:2.5;
color:gray;
font-weight:400;
}
</style>
</head>
<body unresolved>
<p>A `google-signin` looks like this:</p>
<div id="status"></div>
<google-signin clientId="651124942659.apps.googleusercontent.com" scopes="profile"></google-signin>
<!-- Just for demonstration purposes -->
<template id="profile" bind="{{ profile }}">
<div class="card">
<h1><strong>{{displayName}}</strong></h1>
<h2>Is currently signed-in</h2>
<div class="map">
<p>
<strong>Gender</strong> {{gender}}
</p>
<p>
<strong>Skills</strong> {{skills}}
</p>
<p>
<strong>Avatar</strong>
<p>
<img src="{{image.url}}" />
</p>
</p>
<p>
<strong>G+ URL</strong> <a href="{{url}}">{{url}}</a>
</p>
</div>
</div>
</template>
<google-calendar-list title="Calendar Test"></google-calendar-list>
<script>
document.addEventListener("google-signin-success", function(e) {
// Access the GAPI instance passed back from authorization
var gapi = e.detail.gapi;
// Load V1 of the G+ API
gapi.client.load('plus', 'v1', function() {
// To retreive profile information for a user, use the
// people.get API method. For profile info for the currently
// authorized user, use the userId value of me.
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function(resp) {
// Some useful profile info is now available via
// resp.displayName, resp.skills etc
// We can render this info in a template
console.log(resp);
var t = document.querySelector("#profile");
t.model = {};
t.model.profile = resp;
});
});
document.querySelector("#status").innerHTML = "You are now signed in.";
});
document.addEventListener("google-signed-out", function() {
document.querySelector("#status").innerHTML = "You are now signed out.";
});
document.addEventListener("google-signout-attempted", function() {
document.querySelector("#status").innerHTML = "You attempted to sign out.";
});
</script>
</body>
</html>
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../google-signin-aware/google-signin-aware.html">
<link rel="import" href="../google-apis/google-apis.html">
<!--
Element loading Google Calendar API.
##### Example
<google-calendar-api id="calendar"></google-calendar-api>
<script>
window.addEventListener('api-load', function() {
var request = document.getElementById('calendar').api.calendarList.list();
request.execute(function(resp) {
console.log(resp);
});
});
</script>
@element google-calendar-api
@blurb Element loading Google Calendar API.
@status alpha
@url http://googlewebcomponents.github.io/google-calendar
-->
<polymer-element name="google-calendar-api"
attributes="version"
extends="google-client-api"
on-client-api-load="{{loadCalendarApi}}">
<script>
(function() {
var loader = null;
Polymer('google-calendar-api', {
/**
* Called when the Calendar API is loaded.
* @event api-load
*/
/**
* Version of the API to load, e.g. 'v3'.
* @attribute version
* @type string
*/
version: 'v3',
/**
* Returns the loaded Calendar API.
* @method api
*/
get api() {
return (window.gapi && window.gapi.client) ? window.gapi.client.calendar : undefined;
},
notify: function() {
this.fire('client-api-load', arguments);
},
loadCalendarApi: function(e) {
if (gapi.client.calendar) {
this.fire(this.notifyEvent, e.detail);
} else if (loader) {
loader.addEventListener(loader.notifyEvent, function() {
this.fire(this.notifyEvent, e.detail);
}.bind(this));
} else {
loader = this;
gapi.client.load('calendar', this.version,
this.fire.bind(this, this.notifyEvent, e.detail)
);
}
}
});
})();
</script>
</polymer-element>
<!--
Element providing a list of Google Calendars for a signed in user.
##### Example
<google-calendar-list title="What I'm up to"></google-calendar-list>
@element google-calendar-list
@blurb Element providing a list of Google Calendars for a signed in user.
@status alpha
@url http://googlewebcomponents.github.io/google-calendar
-->
<polymer-element name="google-calendar-list">
<template>
<style>
:host, span {
display: inline-block;
}
ul {
list-style: none;
padding: 0;
}
li {
font-family: Arial, sans-serif;
display: block;
list-style: none;
width: 300px;
border-radius: .2em;
padding: .2em;
margin: .2em;
overflow: hidden;
}
li a {
color: inherit;
display: block;
text-decoration: none;
}
google-signin {
float: right;
}
</style>
<google-calendar-api id="calendar" on-api-load="{{displayCalendars}}"></google-calendar-api>
<google-signin-aware
scopes="https://www.googleapis.com/auth/calendar.readonly"
on-google-signin-aware-success="{{signIn}}"></google-signin-aware>
<ul id="calendars">
<li>
{{title || 'My calendars'}}
</li>
<template repeat="{{c in calendars}}">
<li style="background-color: {{c.backgroundColor}}">
<a href="https://www.google.com/calendar/embed?src={{c.id}}&ctz={{c.timeZone}}" target="_blank">
{{c.summary}}
</a>
</li>
</template>
</ul>
</template>
<script>
Polymer('google-calendar-list', {
apikey: null,
signedIn: false,
/**
* A title to be displayed on top of the calendar list.
* @attribute title
* @type string
*/
title: 'My calendars',
signIn: function() {
this.signedIn = true;
this.displayCalendars();
},
/**
* Displays the calendar list if the user is signed in to Google.
*
* @method displayCalendars
*/
displayCalendars: function() {
if (this.signedIn && this.$.calendar.api) {
var request = this.$.calendar.api.calendarList.list();
request.execute(function(resp) {
this.calendars = resp.items;
}.bind(this));
}
}
});
</script>
</polymer-element>
<!--
A badge showing the free/busy status based on the events in a given calendar.
##### Example
<google-calendar-busy-now
calendarId="YOUR_CAL_ID"
apiKey="YOUR_API_KEY"
busyLabel="Do not disturb"
freeLabel="I'm free, talk to me!">
</google-calendar-busy-now>
@element google-calendar-busy-now
@blurb A badge showing the free/busy status based on the events in a given calendar.
@status alpha
@url googlewebcomponent.github.io/google-calendar
-->
<polymer-element name="google-calendar-busy-now"
attributes="calendarId busyLabel freeLabel apiKey">
<template>
<style no-shim>
span {
font-family: Arial, sans-serif;
display: inline-block;
border-radius: .2em;
padding: .2em;
margin: .2em;
overflow: hidden;
}
.busy {
background-color: #FA573C;
}
.free {
background-color: #7BD148;
}
.na {
background-color: #999;
}
</style>
<google-calendar-api xid="2" id="calendar" on-api-load="{{displayBusy}}"></google-calendar-api>
<span class="{{className}}">{{label}}</span>
</template>
<script>
(function() {
var MS_PER_MINUTE = 60000;
var TIME_SPAN = 30;
Polymer('google-calendar-busy-now', {
/**
* Event from this calendar decide whether the status is free/busy.
* @attribute calendarId
* @type string
*/
calendarId: null,
/**
* API key to use with Calendar API requests.
* @attribute apiKey
* @type string
*/
apiKey: null,
/**
* Label to be displayed if the status is busy.
* @attribute busyLabel
* @type string
*/
busyLabel: 'I\'m busy',
/**
* Label to be displayed if the status is free.
* @attribute freeLabel
* @type string
*/
freeLabel: 'I\'m free',
className: '',
label: '',
calendarIdChanged: function() {
this.displayBusy();
},
/**
* Displays the busy/free status.
* @method displayBusy
*/
displayBusy: function() {
if (!this.calendarId) {
console.log('CalendarId is required for this component');
return;
}
if (this.$.calendar.api) {
if (this.apiKey) {
gapi.client.setApiKey(this.apiKey);
}
var now = new Date();
var query = {
timeMin: now.toISOString(),
timeMax: new Date(now.valueOf() +
TIME_SPAN * MS_PER_MINUTE).toISOString(),
items: [
{
id: this.calendarId
}
]
}
var request = this.$.calendar.api.freebusy.query(query);
request.execute(function(resp) {
if (!resp.calendars) {
this.label = this.freeLabel;
this.className = 'free';
return;
}
if (resp.calendars[this.calendarId].errors) {
this.label = 'n/a';
this.className = 'na'
return;
}
var now = new Date();
var busyTimes = resp.calendars[this.calendarId];
for (var i = 0, busyTime; busyTime = busyTimes.busy[i]; i++) {
var start = new Date(busyTime.start);
var end = new Date(busyTime.end);
var busy = start < now && now < end;
this.label = busy ? this.busyLabel : this.freeLabel;
this.className = busy ? 'busy' : 'free';
if (busy) {
break;
}
}
}.bind(this));
}
}
});
})();
</script>
</polymer-element>
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../polymer-signals/polymer-signals.html">
<polymer-element name="google-signin-aware" attributes="scopes">
<template>
<polymer-signals on-polymer-signal-google-auth-success="{{authSuccess}}"></polymer-signals>
</template>
<script>
(function() {
var loader = null;
Polymer('google-signin-aware', {
scopes: '',
attached: function() {
this.fire('polymer-signal', {
name: 'google-auth-request',
data: this.scopes
});
},
authSuccess: function (e, detail, sender) {
// Check if correct scopes authorized, if not we will have to wait
var complete = false;
if (detail && detail.scopes) {
var scopes = this.scopes.split(' ');
complete = true;
for (var i = 0; i < scopes.length; i++) {
if (scopes[i] !== '' && !detail.scopes[scopes[i].toLowerCase()]) {
complete = false;
break;
}
}
}
if (complete) {
this.fire('google-signin-aware-success');
}
}
});
})();
</script>
</polymer-element>
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../google-apis/google-apis.html">
<link rel="import" href="../polymer-signals/polymer-signals.html">
<!--
Copyright (c) 2014 Google Inc. All rights reserved.
LICENSE: github.com/GoogleWebComponents/google-signin/blob/master/LICENSE
AUTHOR(s): Addy Osmani and Rob Dodson.
--->
<!--
google-signin is used to authenticate with Google, allowing you to interact with other Google
APIs such as Drive and Google+.
The attribute `clientId` is provided in your Google Developers Console (https://console.developers.google.com). The `scopes` attribute allows
you to specify which scope permissions are required (e.g do you want to allow interaction with the Google Drive API). The `requestVisibleActions` attribute is necessary if you want to write app activities
(https://developers.google.com/+/web/app-activities/) on behalf of the user. Please note that this
attribute is only valid in combination with the plus.login scope (https://www.googleapis.com/auth/plus.login).
The `labelSignin` attribute is an optional piece of text used for customizing the label on the sign-in button. `labelSignout` allows you to customize the label for sign-out. The `google-signin-success` event is triggered when a user successfully authenticates and `google-signin-failure` is triggered when this is not the case. Both events will also provide the data returned by the Google client authentication process.
Additional events, such as `google-signout-attempted` and `google-signed-out` are triggered when the user
attempts to sign-out and successfully signs out.
##### Example
<google-signin cliendId="..." scopes="https://www.googleapis.com/auth/drive"></google-signin>
<google-signin labelSignin="Sign-in" cliendId="..." scopes="https://www.googleapis.com/auth/drive"></google-signin>
@class google-signin
@blurb A Polymer element for authenticating and authorizing with Google Services.
@status alpha
@homepage http://googlewebcomponents.github.io/google-signin
-->
<polymer-element name="google-signin" attributes="clientId scopes cookiePolicy requestVisibleActions labelSignin labelSignout labelAdditional">
<template>
<style>
:host {
display: inline-block;
}
</style>
<google-client-api></google-client-api>
<polymer-signals on-polymer-signal-google-auth-request="{{authRequest}}"></polymer-signals>
<template if="{{ !signedIn }}">
<input type="button" value="{{labelSignin}}" on-click="{{ signIn }}" />
</template>
<template if="{{ signedIn && !additionalAuth }}">
<input type="button" value="{{labelSignout}}" on-click="{{ signOut }}" />
</template>
<template if="{{ signedIn && additionalAuth }}">
<input type="button" value="{{labelAdditional}}" on-click="{{ signIn }}" />
</template>
</template>
<script>
(function() {
var CLIENT_ID = '';
var SCOPES = [];
var REQUEST_VISIBLE_ACTIONS = '';
var COOKIE_POLICY = '';
var handler;
var authorized_scopes = {};
/**
* Checks whether authorized and requested scopes match and
* displays button for additional auth if necessary
*/
function checkScopes() {
handler.additionalAuth = false;
for (var i = 0; i < SCOPES.length; i++) {
if (SCOPES[i] !== '') {
if (!authorized_scopes[SCOPES[i].toLowerCase()]) {
handler.additionalAuth = true;
break;
}
}
}
}
/**
* Called when authorization server replies.
*
* @param {Object} authResult Authorization result.
* @event google-signin-success
*/
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
// Access token has been successfully retrieved
// Store authorized scopes to check against for new requests
authorized_scopes = {}
var tmp_scopes = authResult.scope.split(' ');
for (var i = 0; i < tmp_scopes.length; i++) {
if (tmp_scopes[i] !== "") {
authorized_scopes[tmp_scopes[i].toLowerCase()] = true;
if (tmp_scopes[i] === 'https://www.googleapis.com/auth/userinfo.profile') {
authorized_scopes['profile'] = true;
}
if (tmp_scopes[i] === 'https://www.googleapis.com/auth/userinfo.email') {
authorized_scopes['email'] = true;
}
}
}
// Trigger the google-signin-success event
handler.fire('polymer-signal', {
name: 'google-auth-success',
data: {result: authResult, scopes: authorized_scopes}
});
handler.fire('google-signin-success', {result: authResult, gapi: gapi});
handler.signedIn = true;
checkScopes();
} else {
if (authResult && authResult.error == "user_signed_out") {
// Fire event to indicate user signed out
handler.fire('google-signed-out', {result: authResult});
} else {
// Fire event to indicate sign-in was not successful
handler.fire('google-signin-failure', {result: authResult});
}
authorized_scopes = {};
// No access token could be retrieved, show the button to start the authorization flow.
handler.signedIn = false;
}
handler.flowComplete = true;
}
Polymer('google-signin', {
/**
* a Google Developers clientId reference
*
* @attribute clientId
* @type string
*/
clientId: '',
/**
* The scopes to provide access to (e.g https://www.googleapis.com/auth/drive) and should be space-delimited.
*
* @attribute scopes
* @type string
* @default 'profile'
*/
scopes: 'profile',
/**
* The cookie policy defines what URIs have access to the session cookie
* remembering the user's sign-in state.
* See https://developers.google.com/+/web/signin/reference#determining_a_value_for_cookie_policy
*
* @attribute cookiePolicy
* @type string
* @default 'single_host_origin'
*/
cookiePolicy: 'single_host_origin',
/**
* The app activity types you want to write on behalf of the user
* (e.g http://schemas.google.com/AddActivity)
*
* @attribute requestVisibleActions
* @type string
*/
requestVisibleActions: '',
/**
* An optional label for the sign-in button
*
* @attribute labelSignin
* @type string
* @default 'Authorize'
*/
labelSignin: 'Authorize',
/**
* An optional label for the sign-out button
*
* @attribute labelSignout
* @type string
* @default 'Sign out'
*/
labelSignout: 'Sign out',
labelAdditional: 'Additional permissions required',
signedIn: false,
additionalAuth: false,
flowComplete: false,
attached: function() {
if (this.clientId === '') {
throw "A valid clientId is required to use this element";
}
CLIENT_ID = this.clientId;
SCOPES = this.scopes.split(' ');
COOKIE_POLICY = this.cookiePolicy;
REQUEST_VISIBLE_ACTIONS = this.requestVisibleActions;
handler = this;
// For page-level configuration the callback has to be in global namespace
window.handleAuthResult = handleAuthResult;
var meta = document.createElement('meta');
meta.setAttribute('name', 'google-signin-clientid');
meta.setAttribute('content', CLIENT_ID);
document.head.appendChild(meta);
meta = document.createElement('meta');
meta.setAttribute('name', 'google-signin-scope');
meta.setAttribute('content', SCOPES.join(' '));
document.head.appendChild(meta);
meta = document.createElement('meta');
meta.setAttribute('name', 'google-signin-cookiepolicy');
meta.setAttribute('content', COOKIE_POLICY);
document.head.appendChild(meta);
meta = document.createElement('meta');
meta.setAttribute('name', 'google-signin-callback');
meta.setAttribute('content', 'handleAuthResult');
document.head.appendChild(meta);
if (REQUEST_VISIBLE_ACTIONS) {
meta = document.createElement('meta');
meta.setAttribute('name', 'google-signin-requestvisibleactions');
meta.setAttribute('content', REQUEST_VISIBLE_ACTIONS);
document.head.appendChild(meta);
}
},
authRequest: function (e, detail, sender) {
var i, new_scopes, extra_scopes;
if (detail) {
extra_scopes = false;
new_scopes = detail.split(" ");
for (i = 0; i < new_scopes.length; i++) {
if (new_scopes[i] !== "") {
if (!authorized_scopes[new_scopes[i].toLowerCase]) {
extra_scopes = true;
if (SCOPES.indexOf(new_scopes[i]) < 0) {
SCOPES.push(new_scopes[i]);
}
}
}
}
}
if (extra_scopes) {
if (handler.flowComplete) {
handler.additionalAuth = true;
}
} else {
handler.fire('polymer-signal', {
name: 'google-auth-success',
data: {result: gapi.auth.getToken(), scopes: authorized_scopes}
});
}
},
signIn: function () {
handler.flowComplete = false;
gapi.auth.signIn({'scope': SCOPES.join(' ')});
},
signOut: function () {
handler.flowComplete = false;
handler.fire('google-signout-attempted');
gapi.auth.signOut();
}
});
})();
</script>
</polymer-element>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment