2

I really like Django's implementation of using dotenv variables on Heroku and would like to bring it to our angular-cli client (Angular 2).

In order to run the client on Heroku I'm running the app through Node running express server.

  1. Node can access Heroku's env variables using process.env.VARNAME, but I didn't understand how to pass those variables to my app.
    How can I read Heroku's variables in my app?

  2. As far as I understand, when using angular-cli I should use environment.ts/environment.prod.ts files to separate environment settings.

    However, I don't want to upload these vars to Bitbucket - which brought me back to questioning how to set those variables from Heroku's vars (of course process.env.VARNAME doesn't work...)

Is that the recommended practice or am I missing something?

3
  • What are the things you want to inject into the client? They won't be secure there whether in the environment or the source code, because they end up outside your control on the user's device anyway. Commented Mar 19, 2017 at 23:39
  • review heroku : devcenter.heroku.com/articles/… :: environment : process.env.NODE_ENV || 'production', Commented Mar 20, 2017 at 1:49
  • Just found this answer, it's actually what I need but answered as impossible. Anyone knows how to do what's recommended there? "better option may be to have your Angular2 app query your server when it initializes" Commented Mar 20, 2017 at 8:40

2 Answers 2

1

Since your server is a NODE server, it has the potential to do processing, rather than only serve static files. This gives you a number of options.

  1. You could use a templating language processed by your NodeJS server to embed environment variables into your HTML before serving it

  2. You could have a CONFIG type endpoint that contains configuration normally stored in your environment variables. Your app, upon launch, can hit this endpoint and grab configuration data that it can then use later.

These are the first two options that come to mind - but there are numerous ways you can handle this.

The important thing to note is that Angular is a client side javascript framework, meaning there is NO security - anything you send down to Angular can be read by anyone using your Angular app. Therefore, it's important that you don't depend on confidentiality in terms of what you send down to Angular to use.

Sign up to request clarification or add additional context in comments.

Comments

1

WARNING: This is not the most secure way to access config vars from heroku. If you have very sensitive keys that you don't want to be vulnerable then find a more secure way to do this.

I used the Heroku-Client API to pull in Config Vars from a specific heroku app using node.js and use a get request to send them to the front-end.

//server.js
const express = require('express');
const http = require('http');
const path = require('path');
const Heroku = require('heroku-client')
const heroku = new Heroku({ token: process.env.API_TOKEN })
const app = express();

let API_KEY = '';

app.use(express.static(path.join(__dirname, 'dist')));

heroku.request({
  method: 'GET',
  path: 'https://api.heroku.com/apps/name-of-app/config-vars',
  headers: {
  "Accept": "application/vnd.heroku+json; version=3",
  "Authorization": "Bearer "+process.env.API_TOKEN
},
  parseJSON: true
}).then(response => {
  //console.log(response, "heroku api...");
  API_KEY = response.API_KEY;
})

app.get('/heroku-env', function(req, res){
    res.json(TOKEN);
});


app.get('*', (req, res) => {
   res.sendFile(path.join(__dirname, 'dist/index.html'))
});

const port = process.env.PORT || '3001';
app.set('port', port);

const server = http.createServer(app);
server.listen(port, () => console.log(`Running on localhost:${port}`));

Then use a service with HTTP to get the response to the frontend.

//EnvService.js
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse, HttpHeaders, HttpRequest } from '@angular/common/http'
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class EnvService{

  env:Observable<any> = null;

  constructor(private http:HttpClient){}

  getEnv() {
    console.log("trying to get heroku env...");
    this.env = this.http.get('/heroku-env')
    return this.env;
  }
}  

Import the service into app.module then subscribe for the res in your component to access the config vars.

//my.component.js
import { Component, ViewChild, Inject } from '@angular/core';
import { EnvService } from './env.service';

@Component({
  selector: 'my-component',
  templateUrl: './my.component.html',
  styleUrls: ['./my.component.css']
})

export class MyComponent {
   defineToken: string = '';

   constructor(private envService: EnvService) {}

   loadEnv() {
      this.envService
        .getEnv().subscribe(res => {
          this.token = res; 
    })
   }

  ngOnInit() {
    this.loadEnv();
   }
 }

references: https://github.com/heroku/node-heroku-client

3 Comments

Seems promising but how do you make it work with your local environment?
I just made updates to comply with angular5. When I work locally I use the actual keys then make sure to replace them with the ENV vars before committing and pushing back to git and heroku.
Thanks for the updates. Don't you think it would be nice if we could use dotenv module to handle the local env as any other heroku env, using a .env file? Not sure how to do that yet but I'll try to figure it out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.