manfredsteyer / angular-oauth2-oidc Goto Github PK
View Code? Open in Web Editor NEWSupport for OAuth 2 and OpenId Connect (OIDC) in Angular.
License: MIT License
Support for OAuth 2 and OpenId Connect (OIDC) in Angular.
License: MIT License
Hi Manfred,
I just spend over a hour to get things work, but I keep getting this error. As I am out of options, any help would be appreciated.
I took an Angular2 seed and NPM installed angular-oauth2-oidc
At my web.module.ts I did the import and their it will go wrong. Keep getting this error:
Error loading http://localhost:5555/node_modules/angular-oauth2-oidc.js as "angular-oauth2-oidc" from http://localhost:5555/web.module.js
Hi I need help,
anyone getting 400 error with unauthorized client error on submit request, anyone had issue?
click handler
public login() {
console.log('email: ' + this.model.email, 'password: ' + this.model.password);
if(this.model.email && this.model.password != null) {
this.loading = true;
this.oauthService.fetchTokenUsingPasswordFlow(this.model.email, this.model.password).then(
result => {
this.token = this.oauthService.getAccessToken();
},
error => {
alert(error);
console.log(error);
this.token = error;
this.loading = false;
})
}
}
fired on login submit
public configureLogin(){
// URL of the SPA to redirect the user to after login
this.oauthService.redirectUri = window.location.origin;
// The SPA's id. The SPA is registerd with this id at the auth-server
this.oauthService.clientId = "testClient";
// set the scope for the permissions the client should request
// The first three are defined by OIDC. The 4th is a usecase-specific one
this.oauthService.scope = "openid profile email TestScope";
// set to true, to receive also an id_token via OpenId Connect (OIDC) in addition to the
// OAuth2-based access_token
this.oauthService.oidc = true;
this.oauthService.dummyClientSecret = "secret";
// Use setStorage to use sessionStorage or another implementation of the TS-type Storage
// instead of localStorage
this.oauthService.setStorage(sessionStorage);
// The name of the auth-server that has to be mentioned within the token
this.oauthService.issuer = "https://phenomenexauthserver.azurewebsites.net/";
// Load Discovery Document and then try to login the user
this.oauthService.loadDiscoveryDocument().then(() => {
// This method just tries to parse the token(s) within the url when
// the auth-server redirects the user back to the web-app
// It dosn't send the user the the login page
this.oauthService.tryLogin({});
});
}
When are you planning to add support for the Authorization Code Flow?
Should be reasonably easy given that you already implemented all logic for identity, access, and refresh tokens, including refreshing the access token with the refresh token - or am I missing something?
It's not an issue, just asking for help.
I want Steam OpenID (http://steamcommunity.com/dev) but the only information is
"use http://steamcommunity.com/openid as the provider." how to use it with this library ?
If I understand it correctly, it's not discovery documment, just xml with
https://steamcommunity.com/openid/login
Hi! There are some debug logging in a console. Can it be disabled by default?
The logging might be enabled by passing an option to OAuthModule.forRoot()
.
Hi, I'm implementing an OAuth 2.0 client for the first time, so I may be doing something incorrectly, but I believe I need to be able to customize the responseType
parameter. The server I'm working with expects a response_type
of code
for requesting an authorization code. Here is a section of the OAuth 2.0 spec:
response_type
REQUIRED. The value MUST be one of "code" for requesting an authorization code as described by Section 4.1.1, "token" for requesting an access token (implicit grant) as described by Section 4.2.1, or a registered extension value as described by Section 8.4.
-- https://tools.ietf.org/html/rfc6749#page-19
Currently, the responseType
can't be set manually, and can only be set to token
or id_token+token
(if OIDC is being used).
I'm trying to setup the OAuthService to use a user info endpoint and I have defined this as follows:
this.oauthService.userinfoEndpoint = "https://login.microsoftonline.com/common/openid/userinfo";
However, when I look at the directory of the service, it says that userinfoEndpoint: undefined
. Because of this, I'm not able to get the user details.
Is there any method for changing the password ?
I try to include your module in https://github.com/mgechev/angular-seed , anf had error:
(SystemJS) XHR error (404 Not Found) loading http://localhost:5555/jspm_packages/npm/angular-oauth2-oidc/angular-oauth2-oidc.js
after changing system config I have new erorr:
(SystemJS) XHR error (404 Not Found) loading http://localhost:5555/jspm_packages/npm/[email protected]
Someone can explain me, hot it works? Thank you
I created an authservice with all parameters filled in
constructor(private oauthService: OAuthService) {
// Login-Url
this.oauthService.loginUrl = "https://login.microsoftonline.com/TENANT_ID_GUID/oauth2/authorize";
// URL of the SPA to redirect the user to after login
this.oauthService.redirectUri = window.location.origin + "/";
// The SPA's id. Register SPA with this id at the auth-server
this.oauthService.clientId = '';
// set the scope for the permissions the client should request
this.oauthService.scope = "openid profile";
// set to true, to receive also an id_token via OpenId Connect (OIDC) in addition to the
// OAuth2-based access_token
this.oauthService.oidc = true;
//resourceAppId from manifest; required because requesting id_token AND token. Would not be requied for just id_token...
this.oauthService.resource = '';
// Use setStorage to use sessionStorage or another implementation of the TS-type Storage
// instead of localStorage
this.oauthService.setStorage(sessionStorage);
// To also enable single-sign-out set the url for your auth-server's logout-endpoint here
this.oauthService.logoutUrl = "https://login.microsoftonline.com/TENANT_ID_GUID/oauth2/logout?id_token={{id_token}}";
this.oauthService.issuer = "https://sts.windows.net/TENANT_ID_GUID/";
// This method just tries to parse the token(s) within the url when
// the auth-server redirects the user back to the web-app
// It dosn't send the user the the login page
this.oauthService.tryLogin({
onTokenReceived: context => {
var claims = context.idClaims;
var currentUser = {
name: claims.name,
id: claims.unique_name,
roles: claims.roles
};
sessionStorage.setItem('currentUser', JSON.stringify(currentUser));
}
});
}
Then a authguard on homepage for homepage
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private oauthService: OAuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.oauthService.hasValidIdToken()) {
return true;
}
this.oauthService.initImplicitFlow();
return false;
}
}
the this.oauthService.initImplicitFlow(); just keeps looping and refreshing homepage, there is stuff in the url but that's it. It doesn't go to login url, any ideas? here is repo https://github.com/premiumwd/a
so if I opt for manual clicks for logon/logoff, I can get this working no problem with my implicit provider. I'd like to basically say spa as a whole is blocked without authentication.
I've basically put something in place that loads the discovery doc, then tries to login. After that oauthservice .hasIdToken(), I initiate the implicitflow().
No combination of router guards and those checks will end up breaking before we present any user interface, and was wondering how people are achieving this effect. There is no user interface for unauthenticated users. I could just enforce the index.html doesnt get served it not authenticated... but seems like I should be able to achieve this here as well.
My router guard experiments resulted in weird looping between my oidc server and the opening component.
When user profile endpoint is called, the result is stored under "id_token_claims_obj" key which is also used to store id token claims. In my case i use implicit type flow and id token is issued together with access token, then i explicitly call 'loadUserProfile' and it overrides id token claims.
https://github.com/manfredsteyer/angular-oauth2-oidc/blob/master/src/oauth-service.ts#L98
Hello everyone,
I´m trying to build an Angular2 project with IdentityServer4 following this post: [https://www.softwarearchitekt.at/post/2016/07/03/authentication-in-angular-2-with-oauth2-oidc-and-guards-for-the-newest-new-router-english-version.aspx].
The fact is that I can´t run the application because i receive the following error once I load it:
localStorage is not defined at new OAuthService
Thanks and regards
Hello,
I added "angular-oauth2-oidc" dependency
angular-cli.json
"scripts": [
"../node_modules/angular-oauth2-oidc/index.ts"
],
getting this following error
Uncaught SyntaxError: Unexpected token import
at eval ()
at webpackJsonp.../../../../script-loader/addScript.js.module.exports (addScript.js:9)
at Object.../../../../script-loader/index.js!../../../../angular-oauth2-oidc/index.ts (index.ts?3cee:1)
at webpack_require (bootstrap 59ce402…:54)
at Object.2 (scripts.bundle.js:37)
at webpack_require (bootstrap 59ce402…:54)
at webpackJsonpCallback (bootstrap 59ce402…:25)
at scripts.bundle.js:1
When the return URL looks like
https://localhost:6001/#/home?id_token=...&access_token=...&token_type=Bearer
&expires_in=3600&scope=...&state=...&session_state=...
then I get the following JSON from getFragment()
{
"home?id_token": "...",
"access_token": "...",
"token_type": "Bearer",
"expires_in": "3600",
"scope": "...",
"state": "...",
"session_state": "..."
}
obviously, the home?
part should not be in this json. Apparently the issue is because the method getFragment
, which parses everything after the #
sign, instead of everything after the ?
sign:
getFragment() {
if (window.location.hash.indexOf("#") === 0) {
return this.parseQueryString(window.location.hash.substr(1));
} else {
return {};
}
};
it should probably look like:
getFragment() {
const questionMarkPosition = window.location.href.indexOf('?');
if (questionMarkPosition >= 0) {
var queryString = window.location.href.slice(questionMarkPosition + 1);
return this.parseQueryString(queryString);
}
if (window.location.hash.indexOf("#") === 0) {
return this.parseQueryString(window.location.hash.substr(1));
}
return {};
}
};
When I try to use canActivate on a route it always returns false. I am doing an implicit flow and when it redirects back it seems like it does not wait for the service to be aware of the login and it always redirects back to the login page.
`@Injectable()
export class AuthGuardService implements CanActivate {
constructor (
private _oauthService: OAuthService,
private _router: Router
) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.loggedIn) {
return true;
}
//Redirect the user before denying them access to this route
this._router.navigate(['/welcome']);
return false;
}
get loggedIn() {
return this._oauthService.hasValidAccessToken();
}
}`
Hi,
the key for "expires_in" in line 286 of oauth-service.ts seems to be incorrect. Regarding openId Spec
Instead of
this.storeAccessTokenResponse(accessToken, null, parts['expiresIn']);
it should be
this.storeAccessTokenResponse(accessToken, null, parts['expires_in']);
if i'm correct.
The old version of this library had it correct.
Thanks in advance
According to the repository for sha256, it is deprecated and suggested alternatives are sha.js or hash.js.
It seems that the documentation describing the password flow without discovery document is incorrect. The code snippet ends with a line that loads the discovery document (copy/paste issue?).
The snippet should IMO end with something like:
this.oauthService.tokenEndpoint = 'https://steyer-identity-server.azurewebsites.net/identity/connect/token';
this.oauthService.fetchTokenUsingPasswordFlow('max', 'geheim').then(() => {
// ...
});
It would be nice to have a separate property on OAuthService for the postLogoutRedirectUri, so that the service can be configured all at once, rather than having to set the redirectUri before calling logout.
...
public redirectUri = "";
public postLogoutRedirectUri = "";
...
For backward compatibility, the service should fall back on the redirectUri:
...
let logoutUrl: string;
// For backward compatibility
if (this.logoutUrl.indexOf('{{') > -1) {
logoutUrl = this.logoutUrl.replace(/\{\{id_token\}\}/, id_token);
}
else {
logoutUrl = this.logoutUrl + "?id_token_hint="
+ encodeURIComponent(id_token)
+ "&post_logout_redirect_uri="
+ encodeURIComponent(this.postLogoutRedirectUri || this.redirectUri);
}
location.href = logoutUrl;
...
if the user does not successfully login in the idp then an error is returned eg:
EXCEPTION: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'error'
Error: Cannot match any routes. URL Segment: 'error'
at ApplyRedirects.noMatchError (http://localhost:4200/vendor.bundle.js:108860:16) [angular]
at CatchSubscriber.selector (http://localhost:4200/vendor.bundle.js:108829:29) [angular]
at CatchSubscriber.error (http://localhost:4200/vendor.bundle.js:50636:31) [angular]
at MapSubscriber.Subscriber._error (http://localhost:4200/vendor.bundle.js:483:26) [angular]
at MapSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
at MapSubscriber.Subscriber._error (http://localhost:4200/vendor.bundle.js:483:26) [angular]
at MapSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
at MapSubscriber.Subscriber._error (http://localhost:4200/vendor.bundle.js:483:26) [angular]
at MapSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
at LastSubscriber.Subscriber._error (http://localhost:4200/vendor.bundle.js:483:26) [angular]
at LastSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
at MergeAllSubscriber.OuterSubscriber.notifyError (http://localhost:4200/vendor.bundle.js:632:26) [angular]
at InnerSubscriber._error (http://localhost:4200/vendor.bundle.js:115288:21) [angular]
at InnerSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
window.console.error @ VM13634:27
VM13634:27 ORIGINAL STACKTRACE:
window.console.error @ VM13634:27
VM13634:27 Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'error'
Error: Cannot match any routes. URL Segment: 'error'
at ApplyRedirects.noMatchError (apply_redirects.js:149) [angular]
at CatchSubscriber.selector (apply_redirects.js:118) [angular]
at CatchSubscriber.error (catch.js:104) [angular]
at MapSubscriber.Subscriber._error (Subscriber.js:128) [angular]
at MapSubscriber.Subscriber.error (Subscriber.js:102) [angular]
at MapSubscriber.Subscriber._error (Subscriber.js:128) [angular]
at MapSubscriber.Subscriber.error (Subscriber.js:102) [angular]
at MapSubscriber.Subscriber._error (Subscriber.js:128) [angular]
at MapSubscriber.Subscriber.error (Subscriber.js:102) [angular]
at LastSubscriber.Subscriber._error (Subscriber.js:128) [angular]
at LastSubscriber.Subscriber.error (Subscriber.js:102) [angular]
at MergeAllSubscriber.OuterSubscriber.notifyError (OuterSubscriber.js:22) [angular]
at InnerSubscriber._error (InnerSubscriber.js:26) [angular]
at InnerSubscriber.Subscriber.error (Subscriber.js:102) [angular]
at resolvePromise (zone.js:643) [angular]
at resolvePromise (zone.js:619) [angular]
at :4200/vendor.bundle.js:131681:17 [angular]
at Object.onInvokeTask (ng_zone.js:264) [angular]
at ZoneDelegate.invokeTask (zone.js:362) [angular]
at Zone.runTask (zone.js:166) [<root> => angular]
at drainMicroTaskQueue (zone.js:529) [<root>]
window.console.error @ VM13634:27
VM13634:27 Unhandled Promise rejection: Cannot match any routes. URL Segment: 'error' ; Zone: angular ; Task: Promise.then ; Value: ZoneAwareError Error: Cannot match any routes. URL Segment: 'error'
at ApplyRedirects.noMatchError (http://localhost:4200/vendor.bundle.js:108860:16) [angular]
at CatchSubscriber.selector (http://localhost:4200/vendor.bundle.js:108829:29) [angular]
at CatchSubscriber.error (http://localhost:4200/vendor.bundle.js:50636:31) [angular]
at MapSubscriber.Subscriber._error (http://localhost:4200/vendor.bundle.js:483:26) [angular]
at MapSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
at MapSubscriber.Subscriber._error (http://localhost:4200/vendor.bundle.js:483:26) [angular]
at MapSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
at MapSubscriber.Subscriber._error (http://localhost:4200/vendor.bundle.js:483:26) [angular]
at MapSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
at LastSubscriber.Subscriber._error (http://localhost:4200/vendor.bundle.js:483:26) [angular]
at LastSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
at MergeAllSubscriber.OuterSubscriber.notifyError (http://localhost:4200/vendor.bundle.js:632:26) [angular]
at InnerSubscriber._error (http://localhost:4200/vendor.bundle.js:115288:21) [angular]
at InnerSubscriber.Subscriber.error (http://localhost:4200/vendor.bundle.js:457:18) [angular]
window.console.error @ VM13634:27
VM13634:27 ZoneAwareError
This statement in oauth-service.ts imports ALL of rxjs which increases the size of app by a large amount. It's unnecessary.
import { Observable, Observer } from 'rxjs';
replacing it by this:
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
would dramatically reduce the size of the app.
First of all, thanks for this great library! I've been using it to show how to interact with Okta's OIDC and OAuth support.
I'm trying to use it in an Ionic app and I've run into an issue navigating on logout. I posted this question to the Ionic forums to see about how to workaround a logout issue. As you can see, I received a reply that I should simply subscribe to an event to do my navigation. For example:
authService.notifier.subscribe((authed) => {
if (authed) {
this.rootPage = TabsPage;
} else {
this.rootPage = LoginPage;
}
});
Does this library provide that feature?
According to http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken, the at_hash claim contains "the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the access_token value, where the hash algorithm used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE Header". The current implementation only uses SHA-256 and fails to process tokens signed with algorithms such as RS384 and ES512 since they use correspondingly larger hash algorithms for at_hash.
When the users passes credentials, that are not accepted by the identity provider, I would like to detect this and present an error message, pointing the user into the right direction. I cannot seem to get this to work, here is a code snippet:
this.oauthService
.fetchTokenUsingPasswordFlowAndLoadUserProfile(this.user.username, this.user.password)
.then(() => {
console.debug('successfully logged in');
let claims = this.oauthService.getIdentityClaims();
this.loginFailed = false;
})
.catch((err) => {
console.error('error logging in', err);
this.loginFailed = true;
this.errorMessage = this.labels.APP_UNAVAILABLE;
})
The err object is a ProgressEvent and I cannot find anything useful to differentiate the error that happened.
Is this currently supported?
Is it possible to save the token for use later and then verify if the token is valid before requesting a new one?
Edit: Use case would be allowing a user to book mark a certain "page" within the app and then navigate back to it using the saved token instead of requesting a new one and then being redirected back to the landing page.
I know you can change the storage to "localStorage" but the module doesn't seem to utilize the stored key.
In short: OAuthService.logOut(true) clears the identity token from the client application but does not log the user out of the identity server itself.
Angular2 application signs in to Identity Server via OIDC and is redirected back to the angular2 app. The angular2 app has a "logout" button which corresponds to OAuthService.logOut(). The parameter to logOut() is "noRedirectToLogoutUrl?: boolean" which, if true, clears the identity token from the angular2 application but not from the identity server, i.e. if the user tries to log in from the angular2 app, they are automatically signed in by the identity server and redirected back to the angular2 app. To me this is unexpected behavior: I want the user signed out of both the angular2 app AND the identity server.
If instead I call OAuthService.logOut(false) then the behavior is as expected except now the user needs to manually navigate back to the angular2 app (which I want to avoid).
Background/Scenario
In utilizing the library by hitting url 'someurl/1' as the initial page, my app sets the settings for the oauthservice on the app component constructor level. The AuthorizationGuardService then determines you are not authorized by using the oauthservice.hasValidIdToken()
the default route configured to the login component kicks in and calls oauthservice.initImplicitFlow()
triggering the IDP redirects which ultimately is returned to the same login route it came from. We check that oauthservice.hasValidIdToken()
is true then redirect back to the guarded route. which also makes the same oauthService.hasValidIdToken()
call and then an additional api call for permissions. This returns an observable boolean. When the observable/api call resolves, the guard should allow the route to pass through. It doesn't it just sits there without any error and never allows the protected route to load. The router seems to be cancelling navigation when tracing is on.
I removed the calls to the oauthService
and the same method works fine ultimately resolving the protected route. The general code structure is below. Package version is 1.0.20 on angular 4.1.3.
app.component.ts
import { Component, Inject } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { AppConfig } from './app.config';
@Component({
selector: 'my-app',
styleUrls: [ './app.component.scss' ],
templateUrl: './app.component.html'
})
export class AppComponent {
constructor(private _config: AppConfig,
private _oauthService: OAuthService) {
this._oauthService.loginUrl = _config.settings.loginEndpoint;
this._oauthService.redirectUri = _config.settings.redirectUri;
this._oauthService.clientId = _config.settings.clientId;
this._oauthService.scope = _config.settings.scope;
this._oauthService.oidc = _config.settings.oidc;
this._oauthService.tryLogin({});
}
}
login.component.ts
import { Component, OnInit, Inject } from '@angular/core';
import { Router } from '@angular/router';
import { OAuthService } from 'angular-oauth2-oidc';
@Component({
template: ''
})
export class LoginComponent implements OnInit {
constructor(private _oauthService: OAuthService, private _router: Router) {
}
ngOnInit(): void {
let id =1;
if (this._oauthService.hasValidIdToken()) {
if (id)
this._router.navigate(['/someurl', id]);
}
else
this.login();
}
login() {
this._oauthService.initImplicitFlow();
}
}
authorization.guard.service.ts
import { permissionServiceInterface, IPermissionService } from './../permission/permission.service';
import { OAuthService } from 'angular-oauth2-oidc';
import { Observable } from 'rxjs/Observable';
import { CanActivate, ActivatedRouteSnapshot, Router, RouterStateSnapshot, NavigationExtras } from '@angular/router';
import { Inject, Injectable } from '@angular/core';
@Injectable()
export class AuthorizationGuardService implements CanActivate {
constructor(private _oauthService: OAuthService,
private _router: Router,
@Inject(permissionServiceInterface) private _permissionService: IPermissionService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {
let id = route.params['id'];
if (this._oauthService.hasValidIdToken())
return this.checkRoutePermissions(+id);
this._router.navigate(['/login']);
return false;
}
private checkRoutePermissions(id: number): Observable<boolean> {
return this._permissionService.checkAuthority(id);
}
}
permission.service.ts
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';
import { Http, Response } from '@angular/http';
import { Injectable, OpaqueToken } from '@angular/core';
export let permissionServiceInterface = new OpaqueToken('IPermissionService');
export interface IPermissionService {
checkAuthority(id: number): Observable<boolean>;
}
@Injectable()
export class PermisisonService implements IPermissionService {
private _apiUrl: string;
constructor(private _http: Http, private _config: AppConfig,
router: Router) {
super(router);
this._apiUrl = 'someurl';
}
checkAuthority(id: number): Observable<boolean> {
this._apiUrl = 'someurl/id';
return this._http.get(this._apiUrl)
.map((response) => {
return response.json() as boolean;
});
}
}
Hi @manfredsteyer, first of all: great for sharing this, works great with ng 4! however i have a small issue with AD B2C and it's policies.
if i have a discovery url like :
that will resolve in a login url :
https://login.microsoftonline.com/doomsdayb2c.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_1_signin
then the login will not work because the appended querystring (in createLoginUrl) starts with a ? too, that's one too much. do you accept a PR as a fix?
I have this error
Failed to load resource: the server responded with a status of 404 (Not Found)
localhost/:51 (SystemJS) XHR error (404 Not Found) loading http://localhost:5555/node_modules/angular-oauth2-oidc.js
Error: XHR error (404 Not Found) loading http://localhost:5555/node_modules/angular-oauth2-oidc.js
at XMLHttpRequest.wrapFn [as _onreadystatechange] (http://localhost:5555/node_modules/zone.js/dist/zone.js?1486029206310:1039:29) []
at Zone.runTask (http://localhost:5555/node_modules/zone.js/dist/zone.js?1486029206310:151:47) [ => ]
at XMLHttpRequest.ZoneTask.invoke (http://localhost:5555/node_modules/zone.js/dist/zone.js?1486029206310:345:33) []
Error loading http://localhost:5555/node_modules/angular-oauth2-oidc.js as "angular-oauth2-oidc" from http://localhost:5555/app/app.module.js Not expecting this error? Report it at https://github.com/mgechev/angular-seed/issues
(anonymous) @ (index):51
http://localhost:5555/node_modules/angular-oauth2-oidc.js Failed to load resource: the server responded with a status of 404 (Not Found)
The Internet Explorer 11 fails with an "Access Denied" excpetion, but only if the security mode is enabled on the Internet Explorer.
This could be due to fact that the localStorage.getItem('..') ist not called in a try/catch block. (https://stackoverflow.com/questions/20212627/access-denied-for-localstorage-in-ie11-but-only-in-desktop-mode-not-in-metro-mo)
Angular doesn't use typings anymore. Now it has dependency on @types, eg.
"devDependencies": { "@types/node": "^6.0.45", "@types/jasmine": "^2.5.35" }
When imported to project with no typings it throws an error:
npm ERR! [email protected] postinstall: typings install
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] postinstall script 'typings install'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
It's propably due to use of typings, and specifying it only in devDependancies.
This is my configuration:
constructor(private oAuthService: OAuthService) {
this.oAuthService.loginUrl = 'https://slack.com/oauth/authorize';
this.oAuthService.redirectUri = '<redirect_uri>';
this.oAuthService.clientId = '<client_id>';
this.oAuthService.scope = 'commands users:read.email chat:write:bot channels:write channels:read users:read';
this.oAuthService.tryLogin({
onTokenReceived: context => {
console.debug("logged in");
console.debug(context);
}
});
}
Slack redirects to <redirect_uri>
passing the parameters code
and state
.
http://<domain>/?code=<code>&state=<state>
Looking at the oauth page from slack (https://api.slack.com/docs/oauth), these are the following steps:
How can I make it work with Slack?
Hi,
There is a bug in the tryLogin
function. When you have additional state, the state is sent to the IDP as a string, seperated with ;
. This is URL encoded due to it being passed around by the IDP, and then when the code tries to split the string later on, it cannot split the string on the delimiter ;
and so the nonce checking fails.
https://github.com/manfredsteyer/angular-oauth2-oidc/blob/master/src/oauth-service.ts#L282-L294
A fix would be to URL decode the string before splitting the state by ;
.
Cheers
``
Does this support the edge browser?
ERROR in Error encountered resolving symbol values statically. Calling function 'OAuthModule', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol AppModule in directory/oAuth/src/app/app.module.ts, resolving symbol AppModule in directory/oAuth/src/app/app.module.ts
I get the following error after upgrading angular-cli:
ERROR in Error encountered resolving symbol values statically. Calling function 'OAuthModule', function calls are not supported. Consider replacing the function or lambda with a refer
ence to an exported function, resolving symbol AppModule in ...
It looks like there is an error in the angular part, but for the moment i can't use your package and i'm not sure if the angular team will change anything. I've compared your package with working code from FexLayoutModule or MaterialModule, but i don't get the difference... :-(
Here is the issue depending to this:
angular/angular#13931
Perhaps you know a solution for that, or gues whether the problem is in your, mine or the angular part :-)
I'd like to support the following scenario:
At first, this sounds trivial, simply add the proper redirect URI:
oauthService.redirectUri = window.location.href;
until one meets an OpenID Connect provider that does not support wildcards in authorized redirect urls (yes Google, I am looking at you ...)
I guess I could specify a redirect URI like "redirect.html?target=the_deep_link" and hook into the router to intercept this URL, parse the query param, and redirect to the actual target once the token has been verified. This has the advantage that asynchronous token verification (due to asynchronous loading of the discovery document) would be invisible to the actual application route, i.e. a component constructor could issue backend requests without needing to wait for a login promise.
Do you see a better solution? If not, would you accept a PR implementing this?
I have the following configured in my AppComponent:
export class AppComponent {
constructor(private router: Router,
private oauthService: OAuthService) {
// Login-Url
this.oauthService.loginUrl = "https://login.microsoftonline.com/TENANT_ID_GUID/oauth2/authorize";
// URL of the SPA to redirect the user to after login
this.oauthService.redirectUri = window.location.origin + "/";
// The SPA's id. Register SPA with this id at the auth-server
this.oauthService.clientId = CLIENT_ID_GUID;
// set the scope for the permissions the client should request
this.oauthService.scope = "openid profile";
// set to true, to receive also an id_token via OpenId Connect (OIDC) in addition to the
// OAuth2-based access_token
this.oauthService.oidc = true;
//resourceAppId from manifest; required because requesting id_token AND token. Would not be requied for just id_token...
this.oauthService.resource = RESOURCE_ID_GUID;
// Use setStorage to use sessionStorage or another implementation of the TS-type Storage
// instead of localStorage
this.oauthService.setStorage(sessionStorage);
// To also enable single-sign-out set the url for your auth-server's logout-endpoint here
this.oauthService.logoutUrl = "https://login.microsoftonline.com/TENANT_ID_GUID/oauth2/logout?id_token={{id_token}}";
this.oauthService.issuer = "https://sts.windows.net/TENANT_ID_GUID/";
// This method just tries to parse the token(s) within the url when
// the auth-server redirects the user back to the web-app
// It dosn't send the user the the login page
this.oauthService.tryLogin({
onTokenReceived: context => {
var claims = context.idClaims;
var currentUser = {
name: claims.name,
id: claims.unique_name,
roles: claims.roles
};
sessionStorage.setItem('currentUser', JSON.stringify(currentUser));
}
});
}
When I call oauthService.logOut()
, it does not end the session on the ID provider server (Azure AD). If I call oauthService.getAccessToken()
it returns null
and oauthService.hasValidAccessToken()
returns false
, but if I navigate to my ID provider login page (https://login.microsoftonline.com), my session is still active.
FWIW, I'm using v1.0.20.
when i use password pattern without discovery document, occur errors.
project can not do the right request to the auth-server.
constructor(private oauthService: OAuthService) {
// Login-Url
this.oauthService.loginUrl = 'https://accounts.google.com/o/oauth2/v2/auth'; //Id-Provider?
// URL of the SPA to redirect the user to after login
this.oauthService.redirectUri = window.location.origin;
// The SPA's id. Register SPA with this id at the auth-server
this.oauthService.clientId = '<client-id>';
// set the scope for the permissions the client should request
this.oauthService.scope = 'profile email https://www.googleapis.com/auth/drive';
// set to true, to receive also an id_token via OpenId Connect (OIDC) in addition to the
// OAuth2-based access_token
this.oauthService.oidc = true;
// Use setStorage to use sessionStorage or another implementation of the TS-type Storage
// instead of localStorage
this.oauthService.setStorage(sessionStorage);
this.oauthService.issuer = 'https://www.googleapis.com';
// To also enable single-sign-out set the url for your auth-server's logout-endpoint here
// this.oauthService.logoutUrl = "https://steyer-identity-server.azurewebsites.net/identity/connect/endsession?id_token={{id_token}}";
// Set a dummy secret
// Please note that the auth-server used here demand the client to transmit a client secret, although
// the standard explicitly cites that the password flow can also be used without it. Using a client secret
// does not make sense for a SPA that runs in the browser. That's why the property is called dummyClientSecret
// Using such a dummy secreat is as safe as using no secret.
this.oauthService.dummyClientSecret = '<client-secret>';
// This method just tries to parse the token(s) within the url when
// the auth-server redirects the user back to the web-app
// It dosn't send the user the the login page
this.oauthService.tryLogin({
onTokenReceived: (context) => {
console.log('logged in', context);
}
});
}
Maybe I'm misunderstanding how this is supposed to be working. But I'm attempting to use it for OAuth with a provider that doesn't have a publicly accessible discovery document for their OpenID Configuration. I've tried for hours to get this working but it never actually navigates to the providers login/consent page. If I take the login url that is generated out of the library and paste that in my browser it takes me to their consent screen just as expected. In order to test the theory, I have been able to get a working example using Google as a provider with Document Discovery. If I take the exact values that are extracted from their openid-configuration and set them manually and remove Document Discovery, it stops working and in fact behaves just like the other provider. Below are the configurations I'm using for Google with and without Document Discovery.
With Discovery:
constructor(private oauthService: OAuthService) {
this.oauthService.redirectUri = window.location.origin + '/index.html';
this.oauthService.clientId = '<client-id>';
this.oauthService.scope = 'openid email profile';
this.oauthService.oidc = true;
this.oauthService.setStorage(sessionStorage);
this.oauthService.issuer = 'https://accounts.google.com'
this.oauthService.loadDiscoveryDocument().then(() => {
this.oauthService.tryLogin({
onTokenReceived: context => {
console.log('logged in');
console.log(context);
}
});
});
}
public login(): void {
this.oauthService.initImplicitFlow();
}
Without Discovery:
this.oauthService.loginUrl = 'https://accounts.google.com/o/oauth2/v2/auth';
this.oauthService.tokenEndpoint = 'https://www.googleapis.com/oauth2/v4/token';
this.oauthService.userinfoEndpoint = 'https://www.googleapis.com/oauth2/v3/userinfo';
this.oauthService.redirectUri = window.location.origin + '/index.html';
this.oauthService.clientId = '<client-id>';
this.oauthService.scope = 'openid email profile';
this.oauthService.oidc = true;
this.oauthService.setStorage(sessionStorage);
this.oauthService.issuer = 'https://accounts.google.com';
this.oauthService.tryLogin({});
Hello,
Thank you for this excellent tool. I was wondering if you can provide an example using Facebook or Google login.
I tried but I faced CORS issues.
Thanks for your help !
https://www.npmjs.com/package/angular-oauth2-oidc says this library has an MIT license, but there's no indication of a license on GitHub.
First off, I wanted to thank you for making this project--I've found it super useful, and it's very generous of you to contribute it!
I've been trying to adapt it to an app that uses Angular Universal using this starter template. The rub with Angular Universal in general is that global objects such as window
or localStorage
are not available when the page gets rendered on the server in the context of node (see list of gotchas here).
The approach I was trying out was to create a "mock" storage service to be injected into the OAuthService when it runs on the server. I could then write this service to take auth tokens from the http header of the client request, and pass them along to the OAuthService
through my mock's implementation of the getItem method.
The issue I'm hitting is with this line - which causes the OAuthService
class to (try to) be created with window.LocalStorage
even before I've had a chance to override it with my mock storage service through the setStorage
method. This causes the app to fail to render completely on the server side.
I've found that by modifying that line to instead simply not create a default value (e.g. private _storage: Storage;
instead of private _storage: Storage = localStorage;
, I can get things working. Obviously, making that change could break other people who had relied on the default behavior in a non-universal context.
One suggestion that might work for everyone would be to initialize the _storage variable in the constructor, but only if localStorage actually exists (which is true on the Browser, but not on the Server. This should keep things the same for anyone rendering in the browser, but also enable the server-render scenario as long as you call the setStorage
method to your mock Storage object soon after initializing OAuthService
. Something like this:
private _storage: Storage;
constructor(private http: Http) {
if (typeof localStorage != undefined) {
this._storage = localStorage;
}
//Rest of the constructor
}
Do you like the idea of trying to support Angular Universal? If yes, what do you think of this general approach? I'm happy to submit a pull request, but I wanted to check with you first.
I tried multiple approaches for logging in with GitHub, but it does not log me in. I can approve the app and it returns the code and state in the url, but it does not do the second step and gets the token.
In short: the reference is not needed and causes conflicts with lib-es6.d.ts
Scenario:
npm install @types/core-js --save-dev
npm uninstall @types/core-js --save-dev
/// <reference types="core-js" />
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.