Git Product home page Git Product logo

auth0-angular's People

Contributors

4javier avatar 7opf avatar adamjmcgrath avatar ahasall avatar alexelin avatar crew-security avatar dependabot[bot] avatar evansims avatar ewanharris avatar fearnycompknowhow avatar frederikprijck avatar jorgeparavicini avatar klaascuvelier avatar lbalmaceda avatar lgtm-com[bot] avatar samjulien avatar sarveshbathija avatar snyk-bot avatar sorohan avatar sre-57-opslevel[bot] avatar stevehobbsdev avatar widcket avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

auth0-angular's Issues

Feature Request: Open signup tab by default

Describe the problem you'd like to have solved

I would like signup tab to be displayed by default on the universal login.Leveraging this api, I do not see options for such a feature.

Describe the ideal solution

A parameter to pass to loginWithRedirect similar to other sdks {screen_hint:"signup"}.

Alternatives and current work-arounds

None that I know of, but there seems to be support in the auth-spa-js client. I could be missing something here..

Returned token doesn't include correct audience

Describe the problem

Trying to set up in my app.module.ts :

...
    AuthModule.forRoot({
      domain: "myDomain.eu.auth0.com",
      clientId: "myClientID",
      audience: "myAudience"
    }),
...

When I decode the returned token I get: "aud": "myClientID" not "aud": "myAudience"
So basically my token is useless for my api.

Environment

  • Version of auth0-angular used: 1.3.1
  • Which browsers have you tested in? Chrome
  • Which version of Angular have you tested with? 11
  • Other modules/plugins/libraries that might be involved:

Deny List in AuthHttpInterceptor

Describe the problem you'd like to have solved

I am trying to migrate away from using @auth0/angular-jwt + other old code to auth0-angular. In angular-jwt, I am using the ability to set a deny list as such:

JwtModule.forRoot({
  config: {
    tokenGetter: tokenGetter,
    whitelistedDomains: [ // domains to allow // ],
    blacklistedRoutes: [ // domains to disallow, overriding whiteListedDomains //]
})

However, based on my understanding / reading of current documentation, there is only an option for an allowedList, but none for a corresponding deniedList.

Describe the ideal solution

Be able to specify a deniedList inside the httpInterceptor option within AuthModule.forRoot(.

Alternatives and current work-arounds

Be very explicit in your allowedList instead of wild-carding with *.

HTTP Interceptor: Attach token optionally

Describe the problem you'd like to have solved

Currently I can only decide if I always or never want a token to be attached to a request. I'm not aware of a way to have a token attached to a request if the user is authenticated and to send the request without a token if the user is not authenticated.
This is a problem for Endpoints which serve content to authenticated and un-authenticated users.

Describe the ideal solution

The ideal solution would be for the interceptor to wait till initial authentication procedure is finished and then continue dispatching requests with a token or without.

Alternatives and current work-arounds

My current workaround is a interceptor which calls getAccesssTokenSilently() and adds a token upon success or no token upon error but dispatches the request in both cases. This is not ideal (because I can't just observe the accesstoken), but it works.

Additional context

Other people seem to have the same usecase as me: https://community.auth0.com/t/auth0-angular-http-interceptor-error-when-user-is-not-logged-in/50866/3

Add support to update user metadata ( like auth0.js patchUserMetadata() )

Describe the problem you'd like to have solved

I want my users to be able to update some information about themselves (their user_metadata) via an angular app ( for example: firstname and lastname). Currently I'm not aware of a possibility to do this with auth0-angular.

Describe the ideal solution

auth0.js offers patchUserMetadata() to patch the user metadata. It would be grand if auth0-angular could offer a similar function.

Alternatives and current work-arounds

My current workaround is to create a separate endpoint on my backend service which accepts the user_metadata and forwards it to auth0

Infinite redirect loop

Describe the problem

Our account currently has a rule to check if a user is allowed to access a particular application, and if they do not, it throws an unauthorized error. Note that this user may and likely does have access to other applications, just not this particular application.

When unauthorized error is thrown in the rule, the application using the Angular Auth0 library finds the user to be unauthenticated (which is probably fine) but throws the user into an infinite redirect loop. I believe this is caused by this line

this.navigator.navigateByUrl('/');

We're currently able to prevent this loop by logging the user out in a callback page; however, this is undesirable because the user will need login again to access any of our other applications.

What was the expected behavior?

It would be nice if there were some way to provide a url or function of sorts for errors like this where the user is quasi logged in so we could respond to errors accordingly.

Reproduction

I cannot share a sample, but would be happy privately demo the issue or try to provide further details as needed.

Environment

Please provide the following:

  • Version of auth0-angular used: ^1.2.0
  • Which browsers have you tested in? Chrome
  • Which version of Angular have you tested with? ^10.2.0
  • Other modules/plugins/libraries that might be involved: N/A

Incognito mode + localhost ERROR Error: Uncaught (in promise): Error: Login required

Describe the problem

For the bug to reprocude, following conditions must be met:

  • app is served from localhost (dev mode)
  • using chrome in incognito mode
  • scenario leveraging auth0 interceptor that adds proper token to the request

Due to incognito mode auth0 does not send all the cookies, so instead of getting token silently it does the full flow. Afther that is sucessfully obtains an acess token. Saying that, when above conditions are met, auth0 fails to add the token to the requests and tries to authorize again - this time with propmt param set to none (my gues is ib this moment the lib ties to obtain token silently). In console ERROR Error: Uncaught (in promise): Error: Login required error is visible, and requests are not beeing sent.

5

2

3

4

What was the expected behavior?

The second and following authorization endpoint calls should not happen. Requests should be sent with proper token attached.

Reproduction

  • use auth0 interceptor
  • serve app locally
  • open chrome in incognito mode
  • go to http://localhost:PORT
  • call any endpoint that requires authentication

Environment

user$ not updated after changing claims and renewing tokens silently

Hi!

First of all: Thank you guys for building an awesome library! It saved us a lot of work. Hopefully, this bug report helps to make it even more awesome. Here's what I'm running into.

I'm using the auth0-angular library in our Angular 9 spa and I ran into this issue: In our application, we show the name of the logged-in person. We use the id_token to get the name. We have a way the user can change his name, we use the auth0 API to update his claims in Auth0. In the SPA we use the authService.getAccessTokenSilently({ignoreCache: true}) to renew the access_token and the id_token and we expect it to contain the new name. And it does! When I inspect the localstorage, and copy the id_token from it, and inspect it at jwt.io, I can see that the name has been updated in the id_token correctly, as I expected. But the authService.user$ is not being updated, so the spa does not show the new name.

To be brief, this is my test-case:

Scenario: Renewing tokens after the claims have been changed
Given somebody has logged into my SPA
And the access_token and the id_token have been retrieved and are stored in localstorage/sessionstorage
And the claims of the id_token have changed in Auth0 after the access_token and id_token have been retrieved in the SPA
When the tokens are renewed using authService.getAccessTokenSilently({ignoreCache: true})
Then the authService.user$ observable should be showing values of the changed claims!

Steps to reproduce:

  • Create a spa, and subscribe to the authService.user$ to display the user claims
  • Log into the spa
  • Change the user's claims in manage.auth0.com
  • Call the authService.getAccessTokenSilently({ignoreCache: true})
  • Expected: The claims should display the expected value

Please let me know if this bug report provides enough information to get it fixed. Also, please let me know if it's appreciated if I try to fix it myself and make pull request.

Thanks in advance,

isAuthenticated$ and user$ are not updated after loginWithPopup()

Describe the problem

I have code which logins user using Auth0 Universal Login window by calling loginWithPopup().

What was the expected behavior?

After successful login, I expect isAuthenticated$ and user$ observables to emit new values, but they don't.

Reproduction

I can try to provide simple amp, if you have existing sandbox template/workflow for this.

Allow customized token endpoint

Describe the problem you'd like to have solved

I used this great lib to connect with cognito instead of auth0. Everything works great, but the token endpoint has CORS error. This lib is using /oauth/token as the url. It it hardcoded in the code. If I could change that to /token it would have worked (I tested that with other lib).

Package configuration via service

Describe the problem you'd like to have solved

My organization does not use the angular environment files for build variables because that method forces the application to be rebuilt in every CI/CD environment which introduces instability. Instead, we include an appSettings.json file with our package and let the application query for environment specific variables on load. This means that configuration via the module.forRoot() parameters isn't possible as it replies on a typescript file getting compiled into the app.

Describe the ideal solution

Our internal configuration provider package is designed to grab the values out of appSettings and provide them in a service to the app. Ideally Auth0 would give us the option to delay configuration until services are provided like so:

constructor(
    public configService: NgAppConfigService,
    public auth0: Auth0Service) { 

    const config = this.configService.getconfig();
    this.auth0.initialize(config.auth0Settings);
}

Alternatives and current work-arounds

Our current workaround is to use our internal Auth0 wrapper (@sigao/ng-auth0) that allows for initialization via the service. However, we would like to switch over to using the SDK if possible.

Post-login hook (before redirect callback)

Describe the problem you'd like to have solved

For cases where tasks have to be performed post-login and pre-redirect callback. Maybe call an API to update user meta data, or check for additional user rights. I´ve considered Auth0 Auth Pipelines such as hooks and rules, however, some cases cannot be resolved with these concepts, and you might want to have the code reside in your app. See questions/discussions like the one in this issue #53.

It would be nice to be able to "inject code" that is supposed to be performed post-login and return a boolean before redirect callback is carried out. This might be added to any of the following functions in auth.service.ts: (checkSessionOrCallback, handleRedirectCallback, or shouldHandleCallback).

Login-Dialog always in English

Describe the problem

In my browser German is the default language. However, the login dialog provided by Auth0 is always in English.

What was the expected behavior?

The login dialog should use the language that is configured in the browser.

Reproduction

  1. Use the default login example provided by auth0-angular
  2. Set German as the default language in Chrome

Environment

  • Version of auth0-angular used: 1.0.0
  • Which browsers have you tested in? Chrome
  • Which version of Angular have you tested with? 9.1.0
  • Other modules/plugins/libraries that might be involved:

SSR ( Server-side rendering) and window -reference

Hi, I tried to run my application using server-side rendering (SSR) with Angular Universal but got 'window is not defined' -error.
Problem seems to be in auth.client.ts -file:

return new Auth0Client({
      redirect_uri: redirectUri || window.location.origin,
      client_id: clientId,
      max_age: maxAge,
      ...rest,
      auth0Client: {
        name: useragent.name,
        version: useragent.version,
      },
    });
  }

auth0_error

auth0_error_1

What was the expected behavior?

No "window is not defined" -error.

Reproduction

Environment

  • Version of auth0-angular used: 1.2.0
  • Which browsers have you tested in? Crome
  • Which version of Angular have you tested with? 11.0.0-rc.1
  • Other modules/plugins/libraries that might be involved:

Question about a possible improvement on the logout call

Is it possible to make the auth SDK logout call an observable or a promise?
At the moment my app is very reactive and when the user logs out. There is always time delay until the logout call is completed.

It would be good to hook up this async call into a stream and perform actions based on completion or even errors by having either an observable or promise api.

What do you think? :)

unexpected post-login redirect behavior

Describe the problem

I'm using auth0-angular to provide Auth0 login for the admin module of a small Angular-based web application. I've configured auth0-angular to redirect to my admin route after login. The import config in my main app module looks like this:

AuthModule.forRoot({
      domain: 'MY-DOMAIN.us.auth0.com',
      clientId: 'MY-CLIENTID',
      redirectUri: 'http://localhost:4200/admin',
    }),

Initially this works as expected. I'm redirected back to http://localhost:4200/admin after login. BUT, after the login is processed, auth0-angular then fires Router.navigate('/') and sends me to the application root.

Is this the expected behavior? Instead, I would like to STAY on the '/admin' route after the session is loaded, instead of automatically navigating back to '/'. Is there a way to configure that behavior?

Reproduction

This should be simple to reproduce by configuring a redirectUri to return the user somewhere other than '/'.

Environment

Please provide the following:

  • Version of auth0-angular used: 1.0.0
  • Which browsers have you tested in? Chrome 85.0.4183.83
  • Which version of Angular have you tested with? 9.1.12

Need to refresh to be considerate as authenticated

Describe the problem

Hi !

I have a trouble which I can reproduce with the playground application.

I have two apps : domain1 and domain2 (this last one are your playground application).
There are all configured on the same auth0 domain.

I have to use getAccessTokenSilently() method on domain2 to be authorized to use my API.

When I'm authenticated on domain1 and I want to access to domain2,
I'm first considerate as unauthenticated by the package, which is not good.
But when I refresh the page I'm finally considerate as authenticated.

What was the expected behavior?

I should not have to refresh the page of domain2 to be authenticated.

Reproduction

  1. I'm connected to domain1 with auth0
  2. I want to access to domain2 as user authenticated of domain1
  3. I'm accessing to domain2 but the authService.isAuthenticated$ considers me as unauthenticated.
  4. I'm doing in parallel getAccessTokenSilently to get token for my API, I'm still unauthenticated
  5. I refresh the page, I'm finally considered as authenticated

I have maybe a solution, in the service auth.service.ts we have this

 const checkSessionOrCallback$ = (isCallback: boolean) =>
      iif(
        () => isCallback,
        this.handleRedirectCallback(),
        defer(() => this.auth0Client.checkSession())
      );

We could have this, and it's working in my case :

 const checkSessionOrCallback$ = (isCallback: boolean) =>
      iif(
        () => isCallback,
        this.handleRedirectCallback(),
        defer(() => this.auth0Client.getTokenSilently())
      );

But I'm not sure it's a good solution.

Or, when we use the method of this same service getAccessTokenSilently, and if it successful, we could emit true on the Subject isAuthenticatedSubject$, so that we are authenticated now.

What do you think ?

Environment

The current playground application, with Chromium and Firefox.

Dynamic Configuration injection fails startup.

Describe the problem

following the documentation on dynamically loading configuration causes error on startup. "Configuration must be specified either through AuthModule.forRoot or through AuthClientConfig.set.

I'm sure there's something I'm just not seeing in the docs, but....

attempting to inject AuthService from @auth0/auth0-angular into an Injectable class causes the bootstrapped to fail

What was the expected behavior?

the application to bootstrap and run

Reproduction

  1. copy the configInitializer function from the Dynamic Configuration section of the package description page here
export function configInitializer(
  http: HttpClient,
  config: AuthClientConfig
) {
  return () =>
  http
  .get('assets/config/config.json')
  .toPromise()
  .then((loadedConfig: AuthConfig) => {
    config.set(loadedConfig)
  });  
}
  1. remove the static clientId and domain values from environment.ts
AuthModule.forRoot(),
  1. add the APP_INITIALIZER, again from the documentation
    {
      provide: APP_INITIALIZER,
      useFactory: configInitializer, 
      deps: [HttpClient, AuthClientConfig],
      multi: true,
    },
  1. ng build && ng serve
  2. navigate to localhost:4200
  3. open dev tools
  4. view console error (chrome puts the error @ auth0-auth0-angular.js:18)

Environment

  • Version of auth0-angular used: 1.3.2
  • Which browsers have you tested in? 14.0.3, chrome 88.0, FF Dev 86.0b9
  • Which version of Angular have you tested with? 11
  • Other modules/plugins/libraries that might be involved: NA

Web workers error

Describe the problem

I create a web-worker via Angular CLI and without any configuration the build fail with:

ERROR in ./node_modules/@auth0/auth0-spa-js/dist/auth0-spa-js.production.esm.js
Module parse failed: Cannot read property 'length' of undefined

What was the expected behavior?

Good way to build

Reproduction

  1. Create a web-worker with Angular CLI
ng g web-worker web-worker
  1. Build the project with:
ng build
  1. Get error:
ERROR in ./node_modules/@auth0/auth0-spa-js/dist/auth0-spa-js.production.esm.js
Module parse failed: Cannot read property 'length' of undefined
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
TypeError: Cannot read property 'length' of undefined
    at /home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/worker-plugin/src/index.js:55:46
    at SyncBailHook.eval (eval at create (/home/path/to/project/node_modules/tapable/lib/HookCodeFactory.js:19:10), <anonymous>:5:16)
    at Parser.walkNewExpression (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1822:25)
    at Parser.walkExpression (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1613:10)
    at Parser.walkExpressions (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1569:10)
    at Parser.walkSequenceExpression (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1726:36)
    at Parser.walkExpression (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1619:10)
    at Parser.walkTerminatingStatement (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1081:32)
    at Parser.walkReturnStatement (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1085:8)
    at Parser.walkStatement (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:985:10)
    at Parser.walkStatements (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:868:9)
    at /home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1017:9
    at Parser.inBlockScope (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:2060:3)
    at Parser.walkBlockStatement (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1014:8)
    at Parser.walkStatement (/home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:949:10)
    at /home/path/to/project/node_modules/@angular-devkit/build-angular/node_modules/webpack/lib/Parser.js:1702:10

Environment

  • Version of auth0-angular used: 1.0.0
  • Which version of Angular have you tested with? 10.1.2

AuthService isAuthenticated$ emits true even when the idToken has expired.

Describe the problem

isAuthenticated$ observable of AuthService emits true even when the idToken has expired.
Just to note, user$ observable emits undefined, which is expected.

I have guarded HomeComponent route with AuthGuard available from auth0-angular lib. However even when idToken has expired the canActivate seems to pass (returns true).

import { AuthService } from '@auth0/auth0-angular';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {

  constructor(public auth: AuthService) { }

  ngOnInit(): void {
    this.auth.user$.subscribe(v => console.log(v));
    this.auth.isAuthenticated$.subscribe(v => console.log(v));
  }

}

image

What was the expected behavior?

I'm expecting AuthGuard to fail (canActivate return false) and auth.isAuthenticated$ to emit false.

Reproduction

  • Version of auth0-angular used: 1.3.1
  • Which browsers have you tested in? Chrome
  • Which version of Angular have you tested with? Angular 11
  • Other modules/plugins/libraries that might be involved: -

Update to Angular 11

Describe the problem

Angular is now at version 11. Installing @auth0/auth0-angular is only possible with --force or --legacy-peer-deps arguments.

What was the expected behavior?

We are expecting a clear install without having to force it.

Reproduction

Detail the steps taken to reproduce this error, and whether this issue can be reproduced consistently or if it is intermittent.
Note: If clear, reproducable steps or the smallest sample app demonstrating misbehavior cannot be provided, we may not be able to follow up on this bug report.

  1. Generate new Angular project using the latest stable version
  2. Execute npm i @auth0/auth0-angular
➜ ### git:(master) ✗ npm i
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: @###@1.0.0
npm ERR! Found: @angular/[email protected]
npm ERR! node_modules/@angular/common
npm ERR!   @angular/common@"~11.0.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @angular/common@"^10.0.2" from @auth0/[email protected]
npm ERR! node_modules/@auth0/auth0-angular
npm ERR!   @auth0/auth0-angular@"^1.2.0" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

Environment

Please provide the following:

  • Version of auth0-angular used: ^1.2.0
  • Which browsers have you tested in? CLI
  • Which version of Angular have you tested with? ~11.0.0
  • Other modules/plugins/libraries that might be involved: Clean install

getAccessTokenSilently is not pickig up config changes via authClientConfig.set()

Describe the problem

getAccessTokenSilently ignores auth0Config changes via authClientConfig.set().
Consider this small code snippet:
Line 1-3 sets a changed auth0Config via authClientConfig.set().
Line 4 requests a new token.

const auth0Config = this.authClientConfig.get();
auth0Config.scope += 'someNewScope';
this.authClientConfig.set(auth0Config);
return this.authService.getAccessTokenSilently()

What was the expected behavior?

I would expect getAccessTokenSilenty to get a new token from auth0 using the changed scopes.
Instead it returns the cached token (no network calls shown in the browser network tab).

I used getAccessTokenSilently({ignoreCache: true}) as a workaround.
Now a new token is requested, but with the old scopes.

Only getAccessTokenSilently({ignoreCache: true, scope: auth0Config.scope}) makes a network call using the correct scopes.

I'm not sure, if the old scopes will be used again once I call getAccessTokenSilently without any arguments.

Environment

  • Version of auth0-angular used: 1.3.2
  • Which browsers have you tested in? User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0
  • Which version of Angular have you tested with? 10.2

AuthGuard not firing when access token has expired

Describe the problem

Following the quick start guide when I reduce the Token Expiration (Seconds)* to 30, all routes with the AuthGuard still fire.

What was the expected behaviour?

AuthGuard should redirect to Auth0 universal login page if isAuthenticated is false.

Reproduction

  1. Create a new Angular app
  2. Follow Auth0 Angular quickstart guide
  3. Set API app to Token Expiration (Seconds)* to 30
  4. Protect the user profile component with an AuthGuard
  5. Click on /profile route, user profile successfully displayed
  6. Wait 30 seconds, click back to home and then onto /profile, user profile is not displayed but the AuthGuard has not fired.

Environment

Please provide the following:

  • **Version of auth0-angular used: 1.2
  • **Which browsers have you tested in? Chrome
  • **Which version of Angular have you tested with? 10.2
  • **Other modules/plugins/libraries that might be involved: N/A

redirectUri does not work properly

Describe the problem

redirectUri is not working so it is not possible to redirect the user to some other page after login into the app.

What was the expected behavior?

User gets redirected after loging in.

Reproduction

The problem is easily reproducible with the sample application, here the issue: auth0-samples/auth0-angular-samples#206

Tested on Chrome and Firefox latest versions.

NullInjectorError: No provider for AbstractNavigator

Describe the problem

I keep getting a NullInjectorError in the browser's console when I import AuthService into a component. I have tried adding AuthService as a provider in my app.module.ts as well as in the component, to no avail. I have imported and initialized AuthModule in app.module.ts.
image

What was the expected behavior?

No error should be thrown, I have mirrored the setup from https://auth0.com/docs/quickstart/spa/angular?framed=1&sq=1#configure-auth0

Reproduction

  1. ng new
  2. npm install @auth0/auth0-angular
  3. declare AuthModule.forRoot(...) in module
  4. add private auth: AuthService to AppComponent constructor

Environment

  • Version of auth0-angular used:
    "@auth0/auth0-angular": "^1.0.0"
  • Which browsers have you tested in?
    Chrome, Safari
  • Which version of Angular have you tested with?
    "@angular/core": "~8.2.3"
  • Other modules/plugins/libraries that might be involved:
    none

No error emitted when getAccessTokenSilently fails

Describe the problem

When the access token can no longer be renewed and the authorization server responds with "Login Required", the error$ observable does not appear to emit the error. I'm uncertain how to handle this situation in my application without building my own getAccessTokenSilently function.

What was the expected behavior?

To receive an error message in the error$ observable which my application can then respond to.

  • Version of auth0-angular used: 1.3.1
  • Which browsers have you tested in? Firefox
  • Which version of Angular have you tested with? 11.0.5

Add option to make adding the Authorization header optional

Please do not report security vulnerabilities here. The Responsible Disclosure Program details the procedure for disclosing security issues.

Thank you in advance for helping us to improve this library! Your attention to detail here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the Auth0 Community or Auth0 Support. Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

Currently, the default HttpInterceptor always throws an exception when trying to send a request to an uri in the configured allowedList. I think it would be useful in some cases to be able to configure it so that, for specific endpoints, the interceptor tries to add the Authorization header if possible (i.e. if the user is logged in), but still sends the requests anyway, even if that's not the case.

Describe the ideal solution

Entries in the allowedList could have an aditional field, something like continueOnError (that defaults to false) that essentially means "I would like this to have the header, but I need it to be sent in any case.".

Alternatives and current work-arounds

You can create a custom interceptor that always tries to add the header, but just leaves things untouched if that's not possible.

Additional context

An example use case is an /available-features endpoint, that should return what features should be enabled for a particular user. This should not be inaccessible to requests that are not authorized, but authorization changes the result of requests to this endpoint, as permissions play a role in determining the status of a particular feature for the current user.

AuthService is intercepting calls that are not meant for it

Describe the problem you'd like to have solved

In my application, I am using both @auth0/auth0-angular and angular-oauth2-oidc. Auth0 for external clients and oauth2 for internal clients. My problems arrives when I try to inject auth0-angular AuthService in my interceptor. Now, whenever I try to get a callback for internal clients (that should be answered by angular-oauth2-oidc, Auth0 will try to capture it and return to "/".. triggering an authentication loop. If I don't use AuthService and instead use the official interceptor, everything runs fine.

Describe the ideal solution

Add more checks to make sure the callback is meant for Auth0. Or add a config so that we can control what happened in case an error happened. Personally, I'd prefer if the callback was not answered by Auth0 if it's not meant for it. Maybe it could check if the origin match the expected URL?

Alternatives and current work-arounds

The current workaround is to use the official interceptor and never inject AuthService in an interceptor.

allowedUrls does not seem to behave as explained in the readme

Describe the problem

The readme examples for the allowedList configuration give the idea that it's possible to pass a partial path with a wildcard like /api/*, but in practice this doesn't seem to work. Apparently, the interceptor uses startsWith with everything prior to the wildcard character to check if the token should be added to the request:

request.url.startsWith(value.substr(0, value.length - 1))

So the examples below don't work in practice at the moment:

allowedList: [
      ...

      // Attach access tokens to any calls that start with '/api/'
      '/api/*',

      // Match anything starting with /api/accounts, but also specify the audience and scope the attached
      // access token must have
      {
        uri: '/api/accounts/*',
        tokenOptions: {
          audience: 'http://my-api/',
          scope: 'read:accounts',
        },
      },

What was the expected behavior?

Tell us about the behavior you expected to see

I expected the examples to match reality ;-)

It makes sense to be strict enough with the URL matching to avoid sending bearer tokens all over the internet though ;-)

Extend ng-add to automate registering the AuthModule.forRoot

Please do not report security vulnerabilities here. The Responsible Disclosure Program details the procedure for disclosing security issues.

Thank you in advance for helping us to improve this library! Your attention to detail here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the Auth0 Community or Auth0 Support. Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

Currently ng-add only installs the library and we need to add AuthModule.forRoot manually, we can automate that too with ng-ad.

Describe the ideal solution

We provide promote so user can provide below values while running ng-add
domain: 'YOUR_AUTH0_DOMAIN',
clientId: 'YOUR_AUTH0_CLIENT_ID',

once provided, ng-add will below code
AuthModule.forRoot({
domain: 'YOUR_AUTH0_DOMAIN',
clientId: 'YOUR_AUTH0_CLIENT_ID',
}),

Alternatives and current work-arounds

A clear and concise description of any alternatives you've considered or any work-arounds that are currently in place.

Additional context

I am interested in doing this change, let me know, would be happy to open the PR.

AuthGuard + dynamic configuration + root protection

Describe the problem

When using the HttpInterceptor and the AuthGuard (on the root route ('')) in combination with a dynamic configuration that loads a config.json file, I get the error

Configuration must be specified either through AuthModule.forRoot or through AuthClientConfig.set

My guess here is, that it is sort of an chicken-and-egg problem: In order to load the configuration file which I would then use to call AuthClientConfig.set with - the HttpInterceptor is triggered (since it's an http call), however since no auth0 config was set at that point yet, this results in the error above.

What was the expected behavior?

Maybe make it so that the interceptor config can either be set beforehand (before the rest of the config - like domain, clientId, etc...) so that it won't throw an error if no config was set yet when the dynamic configuration is loaded, or make the interceptor only check calls if a config was set, otherwise just do nothing.

Reproduction

I basically just used the examples from https://github.com/auth0/auth0-angular and combined AuthGuard on AppComponent ('' route), registering an HttpInterceptor and using a dynamic configuration to load a config.json file that contains domain, clientId and redirectUri.

Environment

Please provide the following:

  • **Version of auth0-angular used: 1.2.0
  • **Which browsers have you tested in? Chrome
  • **Which version of Angular have you tested with? 10.1.6
  • **Other modules/plugins/libraries that might be involved: N/A

Support for a Deny/Exception Pattern of endpoints with HttpInterceptorConfig

Describe the problem you'd like to have solved

This request is a follow up to #74. I have a use case that I think may more clearly indicate the need for this functionality. Our .Net Core Web API contains 15 Controllers. 3 of these controllers do not require authorization headers for various reasons. Based on the documentation, my understanding is that I would need to specify each of the 12 Controller that need Authorization as "Allowed".

Describe the ideal solution

I think a better option would be to add support for an 'except' indicator:

httpInterceptor: {
        allowedList: [
          {
            // Allow all API Endpoints
            uri: 'https://MY_DOMAIN/api/*',
          }, {
            // Except this pattern
            uri: '!https://MY_DOMAIN/api/setup*'
          }, {
            // And this pattern
            uri: '!https://MY_DOMAIN/api/public*'
          }
        ]
      }

Alternatives and current work-arounds

I understand the intent of an explicit allowed list, but without the flexibility to easily exclude a subset, it forces developers into more error prone scenarios. If my API needs a new Controller, I would need to remember to manage this list, or suffer frustration of troubleshooting why no token is being passed. Is it an issue with you Rule? Your Action? The App/API config? I believe it simply make for a more consumable, forgivable API.

Additional context

This ! indicator's behavior is inline with other similar implementations like glob patterns.

Get new token only once in interceptor when multiple API requests are made before token request completes

Describe the problem you'd like to have solved

Currently when there is no or expired token and making multiple API requests in parallel or quick succession there is a call to /token on auth0 for each request. This is inefficient and calls to /token are rate limited which could result in unnecessary errors.

Describe the ideal solution

The interceptor should request a new token for the first matching API request and subsequent requests should await the new token.

Alternatives and current work-arounds

Current workaround is to await a single API request prior to any parallel API requests such that the token is already present and valid for the parallel requests.

Additional context

AuthHttpInterceptor adds auth_token instead of id_token

Describe the problem

AuthHttpInterceptor attaches the auth_token to the Authentication header when making an api call (Bearer [auth_token]).
The auth_token is much shorter than the id_token.

What was the expected behavior?

AuthHttpInterceptor attaches the id_token to the Authentication header when making an api call (Bearer [id_token]).
The id_token is much longer than the auth_token.

Reproduction

  1. Add @auth0/auth0-angular to your project
  2. Register AuthHttpInterceptor in the app module
  3. Check the authentication header of an api request in your browser (network tab)

app.module.ts
providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true } ],

Screenshot of browser network tab
grafik

Environment

  • Version of auth0-angular used: 1.0.0
  • Firefox (browser is not relevant)
  • Version of angular: 10.0.2

Anuglar v12 support

Currently, when updating my Angular project to v12, it will report dependencies resolving issue, due to it depends on old Angular 11.

I have to use --force to install it.

AuthService not resolving when accessing claims or user

Describe the problem

  • An Angular resolver is used before default layout component is loaded on the main route of an app.
  • The purpose of the resolver is to use the user.sub to fetch some permissions for the user from an api.
  • The user.sub is being accessed successfully.
  • The call to the api is successful.
  • The resolver never resolvs, resulting in the default layout components hanging.

What was the expected behavior?

// ...
guard: [AuthGuard],
resolve: {
    users: UserResolver
},
component: LayoutComponent,
// ...

Should result in the user being logged in if not already, some details being fetched for the user, and then that data should be then available on the route in the layout component.

Reproduction

  1. Create a basic angular app and follow the steps provides by the auth0-angular documentation to initialize your Auth0 application in the app.module.ts file.
  2. Create a layout component on a route that is protected by an AuthGuard, and resolves the user.
// route
// ...
path: '',
canActivate: [AuthGuard],
resolve: {
    users: UserResolver
},
component: LayoutComponent,
// ...
// user-resolver.ts
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, Router } from '@angular/router';
import { AuthService } from '@auth0/auth0-angular';
import { UserPermissionService } from '@myServices';
import { Observable, of } from 'rxjs';
import { mergeMap, tap } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<User[]> {
    private user;
    constructor(
        private service: UserPermissionService,
        private auth: AuthService,
        private router: Router,
    ) {}
    public resolve(route: ActivatedRouteSnapshot): Observable<User[]> {
        // Old method w/ auth0-spa-js (this worked)
        // ---
        // const auth0Client$ = (from(
        //     createAuth0Client({
        //         domain: this.environment.auth0_domain,
        //         client_id: this.environment.auth0_clientId,
        //         redirect_uri: this.environment.callbackUrl,
        //         response_type: 'token',
        //         audience: this.environment.auth0_audience,
        //         cacheLocation: 'localstorage',
        //     })
        // ) as Observable<Auth0Client>).pipe(
        //     shareReplay(1),
        //     catchError((err) => throwError(err))
        // );
        // ---
        // return auth0Client$.pipe(
        //     concatMap((client: Auth0Client) => from(client.getUser()))
        // ).pipe(
        //     mergeMap((user) => {
        //         return this.userPermission.getUserWithUserId(user.sub).pipe(
        //             tap((users) => {
        //                 console.log('old', users);
        //             })
        //         );
        //     })
        // );

        return this.auth.idTokenClaims$.pipe(
            mergeMap((res) => {
                // Alternatively, return of([]); also does not work here
                return this.service.getUser(res.sub).pipe(
                    tap((users) => {
                        // This fires and I see the correct data
                        console.log('new', users);
                    })
                );
            })
        );
    }
}
  1. Navigate to the layout component. The resolver should complete and the default <p>Layout component works!</p>, but instead fails and is left with blank screen.
    No logs are produced other than the expected console.log('new', users)

Environment

Please provide the following:

  • **Version of auth0-angular used:^1.2.0
  • **Which browsers have you tested in?Chrome
  • **Which version of Angular have you tested with?^10.1.0
  • **Other modules/plugins/libraries that might be involved:Rxjs, Nx

Possible memory leak in user$

Describe the problem

Calling toPromise on the user$ observable seems to cause a never ending request to /oauth/token eventually leading to the browser crashing due to ever increasing memory.

public async getCurrentUser(): Promise<any> {
    return await this.auth.user$.toPromise<any>();
}

What was the expected behavior?

Return a result after the request has been completed.

Reproduction

See description.

Environment

Please provide the following:

  • Version of auth0-angular used: 0.2.1 and 1.0.0
  • Which browsers have you tested in? Chrome
  • Which version of Angular have you tested with? Angular 10
  • Other modules/plugins/libraries that might be involved:

Allow auth0 to work in iOS browsers without enabling "Allow Cross-Website Tracking"

Please do not report security vulnerabilities here. The Responsible Disclosure Program details the procedure for disclosing security issues.

Thank you in advance for helping us to improve this library! Your attention to detail here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the Auth0 Community or Auth0 Support. Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

I've just spent a couple days bashing my head against the wall over why my auth0 app worked on PC, Mac, and Android phones, but not in any browser in iOS. The login works correctly, but it was unable to call my APIs, and get a message from error$ saying 'Login Required'. When I read more about how the httpInterceptor worked by silently logging in using cookies, I looked a bit more into cookie management in iOS browsers, and found that it worked when I enabled the "Allow Cross-Website Tracking" in each browser's settings. I don't know too much about what kind of cookies qualify to be blocked by this setting, but it's certainly not ideal to have to tell the audience for my site to enable this setting just to be able to access it.

Describe the ideal solution

A clear and concise description of what you want to happen.

I don't have a concise plan of action, but the hope is that I can use the httpInterceptor in my site without enabling the Allow Cross-Website Tracking setting in my iOS browser.

Alternatives and current work-arounds

A clear and concise description of any alternatives you've considered or any work-arounds that are currently in place.

The current workaround is to enable this setting.

Additional context

Add any other context or screenshots about the feature request here.

The call to Authorize include httpInterceptor in the queryParams

Describe the problem you'd like to have solved

My identity provider is complaining that the query params I call Authorize with contains the httpInterceptor.

In fact, after looking at the networking tab, it seems I really redirect with httpInterceptor in the params.
[...]&httpInterceptor=%5Bobject%20Object%5D&ui_locales=fr&response_type=code&response_mode=query
If I remove the httpInterceptor from the AuthConfig, it is then not sent in the URL.

Describe the ideal solution

httpInterceptor shouldn't be included in the queryParams call to Authorize.

Alternatives and current work-arounds

Not use the official HttpInterceptor.

Additional context

Since right now, I use multiple Auth Providers, I'm cornered because on one side, there's #86 that force me to use the default interceptor and on the other, there's this queryParams that breaks my Auth0 if I don't use a custom interceptor.

Unable to set httpInterceptor when providing configuration via AuthClientConfig.set

Describe the problem

I am using the new dynamic configuration to set the various Auth0 Config properties like domain, clientId, and httpInterceptor.

Problem - The httpInterceptor uri/audience options aren't being picked up. As a result, my http.get API calls do not have an Authorization header on them.

What was the expected behavior?

Authorization header should appear on API requests when specified in httpInterceptor

Reproduction

Following the Dynamic Configuration instructions, I didn't pass anything in the .forRoot() in app.module.ts imports section.

AuthModule.forRoot()

I set up the App Initializer and HTTP Interceptor:

{
      provide: APP_INITIALIZER,
      useFactory: configInitializer,    // <- pass your initializer function here
      deps: [AuthClientConfig,HttpClient],
      multi: true,
},
{ provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true },

I set the values directly in the configInitializer

function configInitializer(config: AuthClientConfig, http: HttpClient) {

  return () => { config.set({ 
        clientId: "myclientid", 
        domain: "mytenant.eu.auth0.com",
        httpInterceptor: { allowedList: [
            {
                uri: "/api/*",
                tokenOptions: {
                    audience: "my-audience"
                }
            }
        ] }
    }); 
  }
}

The httpInterceptor does not seem to get picked up. The library does not pass any audience when requesting a token, and no Authorization header is present on calls to /api/....

If I just copy paste that configuration back into .forRoot(), all behavior returns to normal, and Authorization header is passed in API requests.

CC @stevehobbsdev please can you try this out, does httpInterceptor work for you?

Environment

  • Version of auth0-angular used:: 1.1.0
  • Which browsers have you tested in?: Firefox
  • Which version of Angular have you tested with?: 10

Enforced redirection to the homepage due to appState.target

Describe the problem you'd like to have solved

I'd like to remove the default behavior of redirection after callback.
Two are the reasons:
1- The application may need an intermediate page due to reset password ( https://auth0.com/docs/rules/redirect-users ), which means that at that time, the user is not logged.
2- I think the callback is enough to redirect the user in the right page. Why introduce another redirection?
I spent a lot of my precious time due to this issue because it wasn't written anywhere in the documentation ( and i think that i'm not the only one ). I didn't understand why it was redirecting the application back to my home page.

Describe the ideal solution

In my opinion, the best solution is to leave this feature only if the developer specifies the app.target property. No redirection, if the property is not specified.
I also recommend to write down this feature in the README.

ERROR: Configuration must be specified either through AuthModule.forRoot or through

Describe the problem

I'm having troubles with dynamic configuration.
According to the log -statements order seems to be correct -> Config should be set.

What was the expected behavior?

Configuration should be set correctly.

Reproduction

AppModule

@NgModule({

  declarations: [
    AppComponent
  ],
    providers: [
    EnvironmentStore,
    {provide: APP_INITIALIZER, useFactory: auth0Factory, deps: [AuthClientConfig, EnvironmentStore], multi: true}
  ]
  imports: [
    AuthModule.forRoot()
  ],
  bootstrap: [AppComponent]
})
export class AppModule {

Factory Method

function auth0Factory(authClientConfig: AuthClientConfig, environmentService: EnvironmentStore): () => Promise<void> {

  return () => {
    const config: AuthenticationConfig = environmentService.config.authentication;
    authClientConfig.set(config.auth0);
    console.log('Called Auth0 factory');
    console.log('Auth config:' + JSON.stringify(authClientConfig.get()));

    return of<void>().toPromise();

  };
}

EnvironmentStore

@Injectable({
  providedIn: 'root'
})
export class EnvironmentStore {

  private readonly _config: GeneralServiceConfig;

  constructor(@Inject(SERVICE_CONFIG_TOKEN) config: GeneralServiceConfig) {
    this._config = config;

    console.log('EnvironmentStore constructor called');
  }

  public get config(): GeneralServiceConfig {
    return this._config;
  }

}

Error

auth0_error

If so, provide steps:

Where applicable, please include:

  • The smallest possible sample app that reproduces the undesirable behavior
  • Log files (redact/remove sensitive information)
  • Application settings (redact/remove sensitive information)
  • Screenshots

Environment

  • Version of auth0-angular used: 1.2.0
  • Which browsers have you tested in? Crome
  • Which version of Angular have you tested with? 10.2
  • Other modules/plugins/libraries that might be involved: -

Limiting State-Reading URLs/Paths

Describe the problem you'd like to have solved

I was adding in another OAuth provider yesterday for my project, Nylas, which I was having redirect back to my app with both query parameters state and code. I noticed Auth0/Angular (which I believe uses this plugin) was attempting to use the state and code parameters on routes I wasn't intending for them to be consumed, threw an exception, then redirected back to the front page of the app.

Describe the ideal solution

I'd like to be able to specify the routes that should be matched when attempting to log in. Since when using Auth0 you're limited to pre-defined redirect paths anyways, it seems like it should be ok to limit the paths at which auth0-spa attempts to detect and digest state and code query parameters in the url.

For example:

Limit the path to: /login/authorize
Or specify which routes to not hit: /app/settings/nylas

Since the two functions in AuthService are private it looks like I can't just extend AuthService and override the functionality.

A solution would be to updating AuthConfig's advancedOptions param to allow specifying an additional function that is checked before or after the current code in shouldHandleFunction() is checked using logical and.

I do like having the option for a simple string config in authModule though, so ideal would be to specify the window route as a string to match on, or simply providing true to only match on the redirectUri string if it is provided.

Alternatives and current work-arounds

Right now I updated it so auth redirects from Nylas first go to the api server, which redirects back to the client with different query parameters. I'd rather not do this because it should go straight back to the app itself.

Additional context

Reposting this over from auth0/auth0-spa-js#646

Error during ng test NullInjectorError: No provider for InjectionToken auth0.client

Describe the problem

I have a "User Service" that in turn uses AuthService in order to fetch the user's profile and generate login / logout buttons.

Local run and production build of my Angular 11 App work just fine but ng test is failing with:

NullInjectorError: No provider for InjectionToken auth0.client!

What was the expected behavior?

The test should pass.
Adding AuthService as a provider in the .spec.ts file does nothing.

Reproduction

  1. Create a new Service that uses AuthService
  2. run ng test on the application.
  3. See the failure

Environment

Angular 11
"@auth0/auth0-angular": "^1.4.0",

Configuration option to automatically preserve query parameters in loginWithRedirect

Describe the problem you'd like to have solved

I would like to have a configuration option where calling loginWithRedirect in AuthService will preserve the query parameters in the current URL instead of just calling redirectUri (which is defaulted to the root).

Currently I do the following which works well, but it took me a while to figure out this is what I needed to do to correctly preserve them:

    this.base.loginWithRedirect({
      appState: {
        target: window.location.search
      }
    });

Describe the ideal solution

The auth configuration object that gets configured from forRoot() has a preserveInitialQueryString boolean option, maybe even defaulted to true. If true then as the very last step, the original query parameters before the loginWithRedirect() call are appended to whatever the target was (usually defaulting to /).

Alternatives and current work-arounds

Currently have to manually include the target: window.location.search in my state. Thinking this could be implemented by modifying the options before forwarding to the auth0Client

Or instead of implementing this as a feature I think a documentation example or a FAQ would be worthwhile.

Thanks!

Does not work with Ionic 5 / Capacitor and Deep Linking: Cookie is not set

Got Auth0 in the compiled capacitor App running like this: https://auth0.com/docs/libraries/auth0-single-page-app-sdk
But it does not work with the angular services: https://auth0.com/docs/quickstart/spa/angular/01-login

I could not find out why. It just does not set the cookie, which is set in the handleRedirectCallback function of the auth-0-spa-client.

And another thing:
My redirect url is app://myapp.com, while my app is running in the capacitor webview on https://myapp.com. With the auth 0 angular service, I get the error, that it is not allowed to be on another URL when calling handleRedirectCallback than the redirect URL was.

Authentication using cypress

Describe the problem you'd like to have solved

I would like to use cypress (cspress.io) to authenticate against auth0-angular.

Describe the ideal

This blogpost exists which describes how to use cypress to authenticate against auth0 https://auth0.com/blog/end-to-end-testing-with-cypress-and-auth0/#Cypress. But the post is not using auth0-angular. We recently migrated over from auth0-spa-js to auth0-angular but now we need a way for our integration tests to login into the app. Can you provide information on how to adapt the code in the blog post for it to work again?

It seems the callback URL is diffrent then before (using a code payload instead of the token itself).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.