Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get id token claims #69

Merged
merged 8 commits into from
Oct 22, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ Access the `user$` observable on the `AuthService` instance to retrieve the user
</ul>
```

### Access ID token claims

Access the `idTokenClaims$` observable on the `AuthService` instance to retrieve the ID token claims. Like the `user$` observable, this observable already heeds the `isAuthenticated$` observable, so you do not need to check if the user is authenticated before using it:

```js
authService.idTokenClaims$.subscribe((claims) => console.log(claims));
```

### Handle errors

Errors in the login flow can be captured by subscribing to the `error$` observable:
Expand Down
60 changes: 56 additions & 4 deletions projects/auth0-angular/src/lib/auth.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { AuthService } from './auth.service';
import { Auth0ClientService } from './auth.client';
import { Auth0Client } from '@auth0/auth0-spa-js';
import { Auth0Client, IdToken } from '@auth0/auth0-spa-js';
import { AbstractNavigator } from './abstract-navigator';
import { filter } from 'rxjs/operators';
import { Location } from '@angular/common';
Expand Down Expand Up @@ -36,6 +36,7 @@ describe('AuthService', () => {
spyOn(auth0Client, 'checkSession').and.resolveTo();
spyOn(auth0Client, 'isAuthenticated').and.resolveTo(false);
spyOn(auth0Client, 'getUser').and.resolveTo(null);
spyOn(auth0Client, 'getIdTokenClaims').and.resolveTo(null);
spyOn(auth0Client, 'logout');
spyOn(auth0Client, 'getTokenSilently').and.resolveTo('__access_token__');

Expand Down Expand Up @@ -126,14 +127,65 @@ describe('AuthService', () => {
});
});

it('should get the user if not authenticated', (done) => {
it('should not get the user if not authenticated', (done) => {
const user = {
name: 'Test User',
};

(auth0Client.isAuthenticated as jasmine.Spy).and.resolveTo(false);
(auth0Client.getUser as jasmine.Spy).and.resolveTo(user);

let value;
service.user$.subscribe((v) => {
value = v;
});

setTimeout(() => {
expect(value).toBeUndefined();
done();
}, 1000);
});
});
7opf marked this conversation as resolved.
Show resolved Hide resolved

describe('The `idTokenClaims` observable', () => {
it('should get the ID token claims if authenticated', (done) => {
const claims: IdToken = {
__raw: 'idToken',
exp: 1602887231,
iat: 1602883631,
iss: 'https://example.eu.auth0.com/',
};

(auth0Client.isAuthenticated as jasmine.Spy).and.resolveTo(true);
(auth0Client.getIdTokenClaims as jasmine.Spy).and.resolveTo(claims);

service.user$.subscribe((value) => {
expect(value).toBeFalsy();
service.idTokenClaims$.subscribe((value) => {
expect(value).toBe(claims);
done();
});
});

it('should not get the ID token claims if not authenticated', (done) => {
const claims: IdToken = {
__raw: 'idToken',
exp: 1602887231,
iat: 1602883631,
iss: 'https://example.eu.auth0.com/',
};

(auth0Client.isAuthenticated as jasmine.Spy).and.resolveTo(false);
(auth0Client.getIdTokenClaims as jasmine.Spy).and.resolveTo(claims);

let value;
service.idTokenClaims$.subscribe((v) => {
value = v;
});

setTimeout(() => {
expect(value).toBeUndefined();
done();
}, 1000);
});
});

describe('when handling the redirect callback', () => {
Expand Down
9 changes: 9 additions & 0 deletions projects/auth0-angular/src/lib/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ export class AuthService implements OnDestroy {
concatMap(() => this.auth0Client.getUser())
);

/**
* Emits ID token claims when `isAuthenticated$` is `true`.
*/
readonly idTokenClaims$ = this.isAuthenticated$.pipe(
filter((authenticated) => authenticated),
distinctUntilChanged(),
concatMap(() => this.auth0Client.getIdTokenClaims())
);

/**
* Emits errors that occur during login, or when checking for an active session on startup.
*/
Expand Down
15 changes: 4 additions & 11 deletions projects/playground/e2e/integration/playground.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
const EMAIL = Cypress.env('USER_EMAIL');
const PASSWORD = Cypress.env('USER_PASSWORD');

if (!EMAIL || !PASSWORD) {
throw new Error(
'You must provide CYPRESS_USER_EMAIL and CYPRESS_USER_PASSWORD environment variables'
);
}
const EMAIL = '[email protected]';
const PASSWORD = '1234';

const loginToAuth0 = () => {
cy.get('.auth0-lock-form')
Expand Down Expand Up @@ -51,14 +45,13 @@ describe('Smoke tests', () => {
it('do redirect login and show user and access token', () => {
cy.visit('/');
cy.get('#login').should('be.visible').click();

cy.url().should('include', 'https://brucke.auth0.com/login');
loginToAuth0();

cy.get('[data-cy=userProfile]').contains(`"email": "${EMAIL}"`);

cy.get('[data-cy=idTokenClaims]').contains('__raw');
frederikprijck marked this conversation as resolved.
Show resolved Hide resolved
cy.get('[data-cy=accessToken]').should('be.empty');
cy.get('#accessToken').click();

cy.get('[data-cy=accessToken]')
.should('not.be.empty')
.invoke('text')
Expand Down
13 changes: 13 additions & 0 deletions projects/playground/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ <h2>Artifacts</h2>
user$ | async | json
}}</textarea>
</li>
<li class="artifact" *ngIf="claims$ | async as claims">
<p>ID token claims:</p>
<textarea
name=""
id=""
cols="50"
rows="15"
data-cy="idTokenClaims"
disabled="true"
>
{{ claims | json }}
</textarea>
</li>
<li class="artifact">
<p>
Access Token: Select a mode and click the button to retrieve the
Expand Down
1 change: 1 addition & 0 deletions projects/playground/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class AppComponent {
isAuthenticated$ = this.auth.isAuthenticated$;
isLoading$ = this.auth.isLoading$;
user$ = this.auth.user$;
claims$ = this.auth.idTokenClaims$;
accessToken = '';
error$ = this.auth.error$;

Expand Down