Browse Source

Add Authorized HTTPS endpoint sample

Change-Id: I6d65e424119869c14dd56b9568ba280b9f373eaf
ryanpbrewster-patch-1
Nicolas Garnier 8 years ago
parent
commit
e21b4f15fe
  1. 10
      README.md
  2. 43
      authorized-https-endpoint/README.md
  3. 5
      authorized-https-endpoint/firebase.json
  4. 63
      authorized-https-endpoint/functions/index.js
  5. 10
      authorized-https-endpoint/functions/package.json
  6. BIN
      authorized-https-endpoint/public/firebase-logo.png
  7. 77
      authorized-https-endpoint/public/index.html
  8. 32
      authorized-https-endpoint/public/main.css
  9. 78
      authorized-https-endpoint/public/main.js
  10. 10
      quickstarts/email-users/README.md
  11. 10
      quickstarts/email-users/database.rules.json
  12. 3
      quickstarts/email-users/firebase.json
  13. 4
      quickstarts/time-server/README.md

10
README.md

@ -32,10 +32,20 @@ This quickstart sample demonstrates using **Cloud Functions** triggered by **Fir
This quickstart sample demonstrates using **Cloud Functions** triggered by **PubSub events**. The functions log the PubSub payload in a Hello world message.
### [Authorized HTTP Endpoint](/authorized-https-endpoint)
This samples shows how to restrict an HTTPS Function to only the Firebase users of your app.
Only users who pass a valid Firebase ID token as a Bearer token in the Authorization header of the HTTP request are authorized to use the function.
Checking the ID token is done with an ExpressJs middleware that also passes the decoded ID token in the Express request object.
Uses an HTTP trigger.
### [Send FCM notifications](fcm-notifications)
This sample demonstrates how to send a Firebase Cloud Messaging (FCM) notification from a Realtime Database triggered Function when users get new followers. The sample also features a Web UI to experience the FCM notification.
Uses a Realtime Database trigger.
### [Authorize with LinkedIn](/linkedin-auth)
Demonstrates how to authorize with a 3rd party sign-in mechanism (LinkedIn in this case), create a Firebase custom auth token, update the user's profile and authorize Firebase.

43
authorized-https-endpoint/README.md

@ -0,0 +1,43 @@
# Authorized HTTPS Endpoint
This samples shows how to restrict an HTTPS Function to only the Firebase users of your app.
Only users who pass a valid Firebase ID token as a Bearer token in the Authorization header of the HTTP request are authorized to use the function.
Checking the ID token is done with an ExpressJs middleware that also passes the decoded ID token in the Express request object.
Once authrorized the function respond with 'Hello <username>'.
This sample comes with a simple web-based UI which code is in [public](public) directory that lets you sign-in Firebase and initiates an authorized XHR to the Function.
## Setting up the sample
1. Create a Firebase Project using the [Firebase Console](https://console.firebase.google.com).
1. Enable the **Google** Provider in the **Auth** section.
1. Clone or download this repo and open the `authenticated-https-endpoint` directory.
1. Paste the Web initialization snippet from: **Firebase Console > Overview > Add Firebase to your web app** in the `public/index.html` where the `TODO` is located.
1. Download a Service Account credentials from: **Firebase Console > ⚙ > Project Settings > SERVICE ACCOUNTS > GENERATE NEW PRIVATE KEY** and save the file as `functions/service-account.json`.
1. Configure the CLI locally by using `firebase use --add` and select your project in the list.
1. You must have the Firebase CLI installed. If you don't have it install it with `npm install -g firebase-tools` and then configure it with `firebase login`.
1. Configure the CLI locally by using `firebase use --add` and select your project in the list.
1. Install dependencies locally by running: `cd functions; npm install; cd -`
## Deploy and test
This sample comes with a web-based UI for testing the function. To test it out:
1. Deploy your project using `firebase deploy`
1. Open the app using `firebase open hosting:site`, this will open a browser.
1. Sign in the web app in the browser using Google Sign-In and delete your account using the button on the web app. You should receive email confirmations for each actions.
## Contributing
We'd love that you contribute to the project. Before doing so please read our [Contributor guide](../CONTRIBUTING.md).
## License
© Google, 2017. Licensed under an [Apache-2](../LICENSE) license.

5
authorized-https-endpoint/firebase.json

@ -0,0 +1,5 @@
{
"hosting": {
"public": "public"
}
}

63
authorized-https-endpoint/functions/index.js

@ -0,0 +1,63 @@
/**
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.
*/
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const credentials = require('./service-account.json');
admin.initializeApp({
credential: admin.credential.cert(credentials),
databaseURL: `https://${credentials.project_id}.firebaseio.com`
});
const express = require('express');
const cors = require('cors')({origin: true});
const app = express();
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const validateFirebaseIdToken = (req, res, next) => {
console.log('Check if request is authorized with Firebase ID token');
if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) {
console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.',
'Make sure you authorize your request by providing the following HTTP header:',
'Authorization: Bearer <Firebase ID Token>');
res.status(403).send('Unauthorized');
return;
}
const idToken = req.headers.authorization.split('Bearer ')[1];
admin.auth().verifyIdToken(idToken).then(decodedIdToken => {
console.log('ID Token correctly decoded', decodedIdToken);
req.user = decodedIdToken;
next();
}).catch(error => {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
});
};
app.use(cors);
app.use(validateFirebaseIdToken);
app.get('*', (req, res) => {
res.send(`Hello ${req.user.name}`);
});
// This HTTPS endpoint can only be accessed by your Firebase Users.
// Requests need to be authorized by providing an `Authorization` HTTP header
// with value `Bearer <Firebase ID Token>`.
exports.authorizedHello = functions.https.onRequest(app);

10
authorized-https-endpoint/functions/package.json

@ -0,0 +1,10 @@
{
"name": "time-server-functions",
"description": "A simple time server using HTTPS Cloud Function",
"dependencies": {
"cors": "^2.8.1",
"express": "^4.14.1",
"firebase-admin": "^4.1.1",
"firebase-functions": "https://storage.googleapis.com/firebase-preview-drop/node/firebase-functions/firebase-functions-preview.latest.tar.gz"
}
}

BIN
authorized-https-endpoint/public/firebase-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

77
authorized-https-endpoint/public/index.html

@ -0,0 +1,77 @@
<!doctype html>
<!--
Copyright 2016 Google Inc. All rights reserved.
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
https://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
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="Demonstrates how to send a welcome email using Firebase Functions.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome email demo</title>
<!-- Material Design Lite -->
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.1.3/material.blue_grey-orange.min.css">
<script defer src="https://code.getmdl.io/1.1.3/material.min.js"></script>
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="demo-layout mdl-layout mdl-js-layout mdl-layout--fixed-header">
<!-- Header section containing title -->
<header class="mdl-layout__header mdl-color-text--white mdl-color--light-blue-700">
<div class="mdl-cell mdl-cell--12-col mdl-cell--12-col-tablet mdl-grid">
<div class="mdl-layout__header-row mdl-cell mdl-cell--12-col mdl-cell--12-col-tablet mdl-cell--8-col-desktop">
<h3>Authorized HTTP Function demo</h3>
</div>
</div>
</header>
<main class="mdl-layout__content mdl-color--grey-100">
<div class="mdl-cell--12-col mdl-cell--12-col-tablet mdl-grid">
<!-- Card containing the sign-in UI -->
<div id="demo-signed-out-card" class="mdl-card mdl-shadow--2dp mdl-cell">
<div class="mdl-card__supporting-text mdl-color-text--grey-600">
<p>
This web application demonstrates how you can send an authorized XHR Request to an HTTPS Function.
<strong>Now sign in!</strong>
</p>
<button id="demo-sign-in-button" class="mdl-color-text--grey-700 mdl-button--raised mdl-button mdl-js-button mdl-js-ripple-effect"><i class="material-icons">account_circle</i> Sign in with Google</button>
</div>
</div>
<!-- Card containing the signed-in UI -->
<div id="demo-signed-in-card" class="mdl-card mdl-shadow--2dp mdl-cell">
<div class="mdl-card__supporting-text mdl-color-text--grey-600">
<p>
Sending Authorized XHR to:<br>
<span id="demo-url"></span><br><br>
Response: <span id="demo-response">...</span>
</p>
<button id="demo-sign-out-button" class="mdl-color-text--grey-700 mdl-button--raised mdl-button mdl-js-button mdl-js-ripple-effect">Sign out</button>
</div>
</div>
</div>
</main>
</div>
<!-- Firebase -->
<!-- ***********************************************************************************************************************
* TODO(DEVELOPER): Paste the initialization snippet from: Firebase Console > Overview > Add Firebase to your web app. *
*********************************************************************************************************************** -->
<script src="main.js"></script>
</body>
</html>

32
quickstarts/email-users/main.css → authorized-https-endpoint/public/main.css

@ -1,5 +1,5 @@
/**
* Copyright 2015 Google Inc. All Rights Reserved.
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -28,35 +28,19 @@ html, body {
.mdl-layout__header-row {
padding: 0;
}
#message-form {
display: flex;
flex-direction: column;
}
#message-form button {
max-width: 300px;
}
#message-list {
padding: 0;
width: 100%;
}
#message-list > div {
padding: 15px;
border-bottom: 1px #f1f1f1 solid;
}
h3 {
background: url('firebase-logo.png') no-repeat;
background-size: 40px;
padding-left: 50px;
}
#demo-signed-out-card,
#demo-signed-in-card,
#demo-subscribe-button,
#demo-unsubscribe-button,
#demo-subscribed-text-container,
#demo-unsubscribed-text-container {
#demo-signed-in-card {
display: none;
}
#demo-subscribe-button,
#demo-unsubscribe-button {
margin-right: 20px;
#demo-url,
#demo-response {
font-weight: bold;
}
#demo-signed-in-card {
width: 600px;
}

78
authorized-https-endpoint/public/main.js

@ -0,0 +1,78 @@
/**
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.
*/
'use strict';
// Initializes the Demo.
function Demo() {
document.addEventListener('DOMContentLoaded', function() {
// Shortcuts to DOM Elements.
this.signInButton = document.getElementById('demo-sign-in-button');
this.signOutButton = document.getElementById('demo-sign-out-button');
this.responseContainer = document.getElementById('demo-response');
this.urlContainer = document.getElementById('demo-url');
this.helloFunctionUrl = 'https://us-central1-' + config.authDomain.split('.')[0] + '.cloudfunctions.net/authorizedHello/';
this.signedOutCard = document.getElementById('demo-signed-out-card');
this.signedInCard = document.getElementById('demo-signed-in-card');
// Bind events.
this.signInButton.addEventListener('click', this.signIn.bind(this));
this.signOutButton.addEventListener('click', this.signOut.bind(this));
firebase.auth().onAuthStateChanged(this.onAuthStateChanged.bind(this));
}.bind(this));
}
// Triggered on Firebase auth state change.
Demo.prototype.onAuthStateChanged = function(user) {
if (user) {
this.urlContainer.textContent = this.helloFunctionUrl;
this.signedOutCard.style.display = 'none';
this.signedInCard.style.display = 'block';
this.startFunctionsRequest();
} else {
this.signedOutCard.style.display = 'block';
this.signedInCard.style.display = 'none';
}
};
// Initiates the sign-in flow using LinkedIn sign in in a popup.
Demo.prototype.signIn = function() {
firebase.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider());
};
// Signs-out of Firebase.
Demo.prototype.signOut = function() {
firebase.auth().signOut();
};
// Does an authenticated request to a Firebase Functions endpoint.
Demo.prototype.startFunctionsRequest = function() {
firebase.auth().currentUser.getToken().then(function(token) {
console.log('Sending request to', this.helloFunctionUrl, 'with ID token', token);
var req = new XMLHttpRequest();
req.onload = function() {
this.responseContainer.innerText = req.responseText;
}.bind(this);
req.onerror = function() {
this.responseContainer.innerText = 'There was an error';
}.bind(this);
req.open('GET', this.helloFunctionUrl, true);
req.setRequestHeader('Authorization', 'Bearer ' + token);
req.send();
}.bind(this));
};
// Load the demo.
window.demo = new Demo();

10
quickstarts/email-users/README.md

@ -44,3 +44,13 @@ This sample comes with a web-based UI for testing the function. To test it out:
1. Deploy your project using `firebase deploy`
1. Open the app using `firebase open hosting:site`, this will open a browser.
1. Sign in the web app in the browser using Google Sign-In and delete your account using the button on the web app. You should receive email confirmations for each actions.
## Contributing
We'd love that you contribute to the project. Before doing so please read our [Contributor guide](../../CONTRIBUTING.md).
## License
© Google, 2016. Licensed under an [Apache-2](../../LICENSE) license.

10
quickstarts/email-users/database.rules.json

@ -1,10 +0,0 @@
{
"rules": {
"users": {
"$uid": {
".read": "auth.uid === $uid",
".write": "auth.uid === $uid"
}
}
}
}

3
quickstarts/email-users/firebase.json

@ -1,7 +1,4 @@
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "public"
}

4
quickstarts/time-server/README.md

@ -16,7 +16,7 @@ Further reading:
### 1. Clone this repo
Clone or download this repo and open the `http` directory.
Clone or download this repo and open the `quickstarts/time-server` directory.
### 2. Create a Firebase project and configure the quickstart
@ -28,7 +28,7 @@ Set up your Firebase project by running `firebase use --add`, select your Projec
### 3. Install the Firebase CLI and enable Functions on your Firebase CLI
You need to have installed the Firebase CLI. If you haven't already run:
You need to have installed the Firebase CLI. If you haven't run:
```bash
npm install -g firebase-tools

Loading…
Cancel
Save