diff --git a/public/docs/_examples/cb-azure-ad-auth/e2e-spec.ts b/public/docs/_examples/cb-azure-ad-auth/e2e-spec.ts
new file mode 100644
index 0000000000..8df56bc768
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/e2e-spec.ts
@@ -0,0 +1,15 @@
+///
+'use strict';
+describe('Azure AD Auth E2E tests', function () {
+
+ let expectedMsg = 'Simple app demonstrates';
+
+ beforeEach(function () {
+ browser.get('');
+ });
+
+ it(`should display: ${expectedMsg}`, function () {
+ expect(element(by.css('p')).getText()).toContain(expectedMsg);
+ });
+
+});
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/.gitignore b/public/docs/_examples/cb-azure-ad-auth/ts/.gitignore
new file mode 100644
index 0000000000..5df8a1e836
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/.gitignore
@@ -0,0 +1 @@
+authSettings.config.ts
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/app.component.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/app.component.ts
new file mode 100644
index 0000000000..cc38f89bf4
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/app.component.ts
@@ -0,0 +1,9 @@
+import { Component } from '@angular/core';
+@Component({
+ selector: 'app',
+ template: `
+ About | Login | Status
+ `
+})
+
+export class AppComponent { }
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/app.module.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/app.module.ts
new file mode 100644
index 0000000000..268ec4c49f
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/app.module.ts
@@ -0,0 +1,39 @@
+import { NgModule } from '@angular/core';
+import { HttpModule } from '@angular/http';
+import { BrowserModule } from '@angular/platform-browser';
+import { routing } from './app.routing';
+import { AppComponent } from './app.component';
+
+import { HomeComponent } from './home/home.component';
+import { LoginComponent } from './login/login.component';
+import { StatusComponent } from './status/status.component';
+
+import {AzureADServiceConstants} from './ngAuth/authenticators/AzureADServiceConstants';
+import {AzureADAuthService} from './ngAuth/authenticators/AzureADAuthService';
+import {AuthenticatedHttpService} from './ngAuth/AuthenticatedHttpService';
+
+import {serviceConstants} from './authsettings.config';
+
+let authenticator = new AzureADAuthService(serviceConstants);
+
+@NgModule({
+ providers: [
+ AuthenticatedHttpService,
+ {
+ provide: AzureADAuthService,
+ useValue: authenticator
+ }],
+ imports: [
+ routing,
+ BrowserModule,
+ HttpModule
+ ],
+ declarations: [
+ AppComponent,
+ HomeComponent,
+ LoginComponent,
+ StatusComponent
+ ],
+ bootstrap: [AppComponent]
+})
+export class AppModule { }
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/app.routing.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/app.routing.ts
new file mode 100644
index 0000000000..22693909b6
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/app.routing.ts
@@ -0,0 +1,12 @@
+import { ModuleWithProviders } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import { LoginComponent } from './login/login.component';
+import {HomeComponent} from './home/home.component';
+import { StatusComponent } from './status/status.component';
+
+export const routes: Routes = [
+ { path: '', component: HomeComponent },
+ { path: 'login', component: LoginComponent },
+ { path: 'status', component: StatusComponent },
+];
+export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/home/home.component.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/home/home.component.ts
new file mode 100644
index 0000000000..d317ce8bc4
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/home/home.component.ts
@@ -0,0 +1,7 @@
+import { Component } from '@angular/core';
+import { Inject, Injectable } from '@angular/core';
+
+@Component({
+ template:'
Simple app demonstrates logging into AzureAD/Office365 and running a command against the MS graph
'
+})
+export class HomeComponent { }
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/login/login.component.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/login/login.component.ts
new file mode 100644
index 0000000000..150fde24f9
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/login/login.component.ts
@@ -0,0 +1,21 @@
+import { Component, Inject } from '@angular/core';
+import { Router } from '@angular/router';
+
+import {AzureADAuthService} from '../ngAuth/authenticators/AzureADAuthService';
+
+@Component({
+ template: `
+ `
+})
+
+export class LoginComponent {
+ constructor(
+ @Inject(AzureADAuthService) private _authService: AzureADAuthService,
+ private _router: Router) { }
+
+ logIn() {
+ this._authService.logIn("/");
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/main.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/main.ts
new file mode 100644
index 0000000000..6801c0441c
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/main.ts
@@ -0,0 +1,3 @@
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import {AppModule} from './app.module';
+platformBrowserDynamic().bootstrapModule(AppModule);
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/AuthenticatedHttpService.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/AuthenticatedHttpService.ts
new file mode 100644
index 0000000000..5bcb744c5c
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/AuthenticatedHttpService.ts
@@ -0,0 +1,32 @@
+import { Injectable, Inject } from '@angular/core';
+import { Http, Headers, Response } from '@angular/http';
+import { AzureADAuthService } from './authenticators/AzureADAuthService';
+import { Observable, Subscriber } from 'rxjs';
+
+@Injectable()
+export class AuthenticatedHttpService {
+ private _authenticator: AzureADAuthService;
+ private _http: Http;
+ constructor( @Inject(Http) http: Http, @Inject(AzureADAuthService) authenticator: AzureADAuthService) {
+ this._authenticator = authenticator;
+ this._http = http;
+ }
+
+ createAuthorizationHeader(headers: Headers) {
+ headers.append('Authorization', 'Bearer ' + this._authenticator.getAccessToken());
+ }
+
+ get(url: string) {
+ let headers = new Headers();
+ this.createAuthorizationHeader(headers);
+ return this._http.get(url, { headers: headers });
+ }
+
+ post(url: string, data: any) {
+ let headers = new Headers();
+ this.createAuthorizationHeader(headers);
+ return this._http.post(url, data, {
+ headers: headers,
+ });
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/JwtHelper.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/JwtHelper.ts
new file mode 100644
index 0000000000..f8f4a595ed
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/JwtHelper.ts
@@ -0,0 +1,30 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class JwtHelper {
+ private urlBase64Decode(str: string) {
+ var output = str.replace(/-/g, '+').replace(/_/g, '/');
+ switch (output.length % 4) {
+ case 0: { break; }
+ case 2: { output += '=='; break; }
+ case 3: { output += '='; break; }
+ default: {
+ throw 'Illegal base64url string!';
+ }
+ }
+ return decodeURIComponent((window).escape(window.atob(output)));
+ }
+
+ public decodeToken(token: string = "") {
+ if (token === null || token === "") return {"upn": ""};
+ var parts = token.split('.');
+ if (parts.length !== 3) {
+ throw new Error('JWT must have 3 parts');
+ }
+ var decoded = this.urlBase64Decode(parts[1]);
+ if (!decoded) {
+ throw new Error('Cannot decode the token');
+ }
+ return JSON.parse(decoded);
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/authenticators/AzureADAuthService.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/authenticators/AzureADAuthService.ts
new file mode 100644
index 0000000000..4d386cc0a0
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/authenticators/AzureADAuthService.ts
@@ -0,0 +1,94 @@
+import { Injectable } from '@angular/core';
+import { Http, Headers } from '@angular/http';
+import { JwtHelper } from '../JwtHelper';
+
+import { AzureADServiceConstants } from "./AzureADServiceConstants";
+
+@Injectable()
+export class AzureADAuthService {
+ public isUserAuthenticated(): boolean {
+ let access_token = this.getAccessToken();
+ return access_token != null;
+ }
+
+ public getAccessToken(): string {
+ return window.localStorage.getItem("access_token");
+ }
+
+ public getUserName(): string {
+ var jwtHelper = new JwtHelper();
+ var parsedToken = jwtHelper.decodeToken(this.getAccessToken());
+
+ var expiryTime = new Date(parsedToken.exp * 1000);
+ var now = new Date();
+ if (now > expiryTime) this.logOut();
+
+ return parsedToken.upn;
+ }
+
+ public logIn(state = "/") {
+ window.location.href = "https://login.microsoftonline.com/" + this._serviceConstants.tenantID +
+ "/oauth2/authorize?response_type=id_token&client_id=" + this._serviceConstants.clientID +
+ "&redirect_uri=" + encodeURIComponent(window.location.href) +
+ "&state=" + state + "&nonce=SomeNonce";
+ }
+
+ public logOut(state = "/") {
+ window.localStorage.removeItem("id_token");
+ window.localStorage.removeItem("access_token");
+ window.location.href = state;
+ }
+
+
+ private parseQueryString = function (url: string) {
+ var params = {};
+ var queryString = "";
+ if (url.search("#") != -1) {
+ queryString = url.substring(url.search("#") + 1);
+
+ } else {
+ queryString = url.substring(url.indexOf("?") + 1);
+ }
+ var a = queryString.split('&');
+ for (var i = 0; i < a.length; i++) {
+ var b = a[i].split('=');
+ params[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
+ }
+ return params;
+ }
+
+ private params = this.parseQueryString(location.hash);
+
+ constructor(private _serviceConstants: AzureADServiceConstants) {
+ // do we have an access token, if so add the iframe renewer
+ if (window.localStorage.getItem("access_token")) {
+ var iframe = document.createElement('iframe');
+ iframe.style.display = "none";
+ iframe.src = "/app/ngAuth/renewToken.html?tenantID=" +
+ encodeURIComponent(this._serviceConstants.tenantID) +
+ "&clientID=" + encodeURIComponent(this._serviceConstants.clientID) +
+ "&resource=" + encodeURIComponent(this._serviceConstants.graphResource);
+ window.onload = function () {
+ document.body.appendChild(iframe);
+ }
+ }
+ if (this.params["id_token"] != null) {
+ window.localStorage.setItem("id_token", this.params["id_token"]);
+ // redirect to get access token here..
+ window.location.href = "https://login.microsoftonline.com/" + this._serviceConstants.tenantID +
+ "/oauth2/authorize?response_type=token&client_id=" + this._serviceConstants.clientID +
+ "&resource=" + this._serviceConstants.graphResource +
+ "&redirect_uri=" + encodeURIComponent(window.location.href) +
+ "&prompt=none&state=" + this.params["state"] + "&nonce=SomeNonce";
+ }
+ else if (this.params["access_token"] != null) {
+ window.localStorage.setItem("access_token", this.params["access_token"]);
+ // redirect to the original call URl here.
+ window.location.href = this.params["state"];
+ }
+ }
+}
+
+function error(err: any) {
+ console.error(JSON.stringify(err, null, 4));
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/authenticators/AzureADServiceConstants.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/authenticators/AzureADServiceConstants.ts
new file mode 100644
index 0000000000..04a2e3fa22
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/authenticators/AzureADServiceConstants.ts
@@ -0,0 +1,13 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class AzureADServiceConstants {
+ constructor(
+ public clientID:string,
+ public tenantID:string,
+ public redirectURL:string,
+ public backendUrl:string,
+ public graphResource = "https://graph.microsoft.com",
+ public isCordova = false,
+ public isElectron = false) {}
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/renewToken.html b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/renewToken.html
new file mode 100644
index 0000000000..de71df64bf
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/ngAuth/renewToken.html
@@ -0,0 +1,58 @@
+
+
+
+ Renew Token
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/app/status/status.component.ts b/public/docs/_examples/cb-azure-ad-auth/ts/app/status/status.component.ts
new file mode 100644
index 0000000000..c9c92791ea
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/app/status/status.component.ts
@@ -0,0 +1,44 @@
+import { Component, Inject } from '@angular/core';
+import { Router } from '@angular/router';
+
+import { AuthenticatedHttpService } from '../ngAuth/AuthenticatedHttpService';
+import { AzureADAuthService } from '../ngAuth/authenticators/AzureADAuthService';
+
+
+@Component({
+ template: `
+
+ userName: {{this._authService.getUserName()}}
+
+
+
+
+
+ -
+ Name: {{file.remoteItem.name}}
+ Size: {{file.size}}
+
+
+
+
+ User is not signed in.
+
+ `
+})
+
+export class StatusComponent {
+ private _files: any[] = [];
+ constructor( @Inject(AzureADAuthService) private _authService: AzureADAuthService, private _authenticatedHttpService: AuthenticatedHttpService) { }
+
+ logOut() {
+ this._authService.logOut("/");
+ }
+
+ runCommand() {
+ this._authenticatedHttpService.get("https://graph.microsoft.com/v1.0/me/drive/recent").subscribe((results => {
+ this._files = results.json().value;
+ }));
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/example-config.json b/public/docs/_examples/cb-azure-ad-auth/ts/example-config.json
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/index.html b/public/docs/_examples/cb-azure-ad-auth/ts/index.html
new file mode 100644
index 0000000000..836a629352
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/index.html
@@ -0,0 +1,23 @@
+
+
+
+ Angular 2 AzureAD/Office365 Auth
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
diff --git a/public/docs/_examples/cb-azure-ad-auth/ts/plnkr.json b/public/docs/_examples/cb-azure-ad-auth/ts/plnkr.json
new file mode 100644
index 0000000000..a4449b444f
--- /dev/null
+++ b/public/docs/_examples/cb-azure-ad-auth/ts/plnkr.json
@@ -0,0 +1,9 @@
+{
+ "description": "QuickStart",
+ "files": [
+ "!**/*.d.ts",
+ "!**/*.js",
+ "!**/*.[1].*"
+ ],
+ "tags": ["quickstart"]
+}
\ No newline at end of file
diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json
index 7a45a91e77..2c56cc3c33 100644
--- a/public/docs/ts/latest/cookbook/_data.json
+++ b/public/docs/ts/latest/cookbook/_data.json
@@ -4,65 +4,57 @@
"navTitle": "Overview",
"description": "A collection of recipes for common Angular application scenarios"
},
-
"aot-compiler": {
"title": "Ahead-of-Time Compilation",
"intro": "Learn how to use Ahead-of-time compilation"
},
-
"a1-a2-quick-reference": {
"title": "Angular 1 to 2 Quick Reference",
"navTitle": "Angular 1 to 2 Quick Ref",
"intro": "Learn how Angular 1 concepts and techniques map to Angular 2"
},
-
"ngmodule-faq": {
"title": "Angular Module FAQs",
"intro": "Answers to frequently asked questions about @NgModule"
},
-
+ "azure-ad-auth": {
+ "title": "AzureAD Authentication",
+ "intro": "Explains how to use Angular to authenticate with AzureAD and Office365"
+ },
"component-communication": {
"title": "Component Interaction",
"intro": "Share information between different directives and components"
},
-
"component-relative-paths": {
"title": "Component-relative Paths",
"intro": "Use relative URLs for component templates and styles."
},
-
"dependency-injection": {
"title": "Dependency Injection",
"intro": "Techniques for Dependency Injection"
},
-
"dynamic-form": {
"title": "Dynamic Forms",
"intro": "Render dynamic forms with FormGroup"
},
-
"form-validation": {
"title": "Form Validation",
"intro": "Validate user's form entries"
},
-
"i18n": {
"title": "Internationalization (i18n)",
"intro": "Translate the app's template text into multiple languages"
},
-
"set-document-title": {
"title": "Set the Document Title",
"intro": "Setting the document or window title using the Title service."
},
-
"ts-to-js": {
"title": "TypeScript to JavaScript",
"intro": "Convert Angular TypeScript examples into ES5 JavaScript"
},
-
"visual-studio-2015": {
"title": "Visual Studio 2015 QuickStart",
"intro": "Use Visual Studio 2015 with the QuickStart files"
}
-}
+}
\ No newline at end of file
diff --git a/public/docs/ts/latest/cookbook/azure-ad-auth.jade b/public/docs/ts/latest/cookbook/azure-ad-auth.jade
new file mode 100644
index 0000000000..05ca93eab1
--- /dev/null
+++ b/public/docs/ts/latest/cookbook/azure-ad-auth.jade
@@ -0,0 +1,13 @@
+include ../_util-fns
+
+:marked
+ This cookbook describes how to authenticate against AzureAD and Office365 using Angular
+
+a#toc
+:marked
+ ## Table of Contents
+
+a#overview
+.l-main-section
+:marked
+ ## Overview
\ No newline at end of file