I'm trying to do authentication with Steam from the home page in Angular but whenever I click on button (which has (click)
event pointing at login()
function in AppComponent
), instead of being redirected to Steam page, current page is refreshed and nothing happens.
This is server-side code:
'use strict';
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
const jwt = require('express-jwt');
const cors = require('cors');
const passport = require('passport');
const SteamStrategy = require('passport-steam').Strategy;
const mongoose = require('mongoose');
app.use(cors());
mongoose.connect('mongodb://localhost:27017/database_test');
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((obj, done) => {
done(null, obj);
});
passport.use(new SteamStrategy({
returnURL: 'http://localhost:3000/auth/steam/return',
realm: 'http://localhost:3000',
apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
},
(identifier, profile, done) => {
process.nextTick(() => {
profile.identifier = identifier;
return done(null, profile);
});
}
));
app.use(passport.initialize());
app.use(passport.session());
app.get('/auth/steam',
passport.authenticate('steam', { failureRedirect: 'http://localhost:4200/home' }),
(req, res) => {
res.json({"success": true, "res": res});
}
);
app.get('/auth/steam/return',
passport.authenticate('steam', { failureRedirect: 'http://localhost:4200/home' }),
(req, res) => {
res.json({"success": true, "res": res});
}
);
server.listen(3000, () => {
console.log('Backend listening on port 3000.');
});
This is AuthenticationService
:
import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs';
import { JwtHelper, tokenNotExpired } from 'angular2-jwt';
import 'rxjs/add/operator/map';
@Injectable()
export class AuthenticationService {
domain = 'http://localhost:3000';
constructor(private http: Http) { }
login() {
return this.http.get(this.domain + '/auth/steam').map(res => res.json());
}
}
This is AppComponent
:
import { Component } from '@angular/core';
import { AuthenticationService } from './authentication.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [ AuthenticationService ]
})
export class AppComponent {
constructor(private authService: AuthenticationService) { }
login(): void {
this.authService.login().subscribe(data => {
alert(data);
});
}
}
Both servers are running (Angular and Node).
Edit: I added button instead of link and log showed me there is an error with Same-origin policy.
Simply said, you can't redirect your Angular service to your backend=>steam=>backend callback url. You have to redirect the user there.
So instead of calling the authService.login()
, just add a direct link, like said elsewhere. I don't see the first link in your backend code, but frontend code suggests /auth/steam
like in SteamStrategy docs.
So, step 1 is this:
// change the login() method on AuthService
login() {
window.location.href = "http://localhost:3000/auth/steam";
}
(You'll want to take that URL from environment
or some such later on.)
What happens now:
localhost:3000/auth/steam
http://localhost:3000/auth/steam/return
What happens next?
then, redirect the user back to Angular app. Something like this:
res.redirect('/public/#/authcallback
)`
(Using HashLocationStrategy here so you see clearly where I was redirecting you.)
/authcallback
route in Angular should probably hit the endpoint directly once more, to get the auth data, before doing it's own redirects.Alternatives:
Now, that last part could be done differently. You could do something like redirect from node back to index or to whatever the original route was (you could add those as params etc). Then, have an Angular service, that always checks back with backend if there is auth data.
Or you could have your node backend embed the info in Angular's index.html
or whatever page you're using. You know, old-school, server-side inject data in maybe a script tag with something like ejs
or jade
. It would be faster, but I'd still not trust it blindly on client (or server) and would double-check, maybe in background.
What you are doing in your code calls a GET request to your own server. I dont see any page redirection at all.
If you want to redirect the user to an external website you need to send the user there, either :
From HTML file :
<a href="http://example.com">Link to steam</a>
From your component .ts file:
window.location.href = 'http://www.example.com'
If you want to redirect the user to another page on your website, you need to use the Angular Router :
From HTML file :
<a routerLink="/component-one">Component One</a>
From your component .ts file :
this.router.navigate(['/component-one']);
So you component now becomes :
import { Component } from '@angular/core';
import { AuthenticationService } from './authentication.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [ AuthenticationService ] // This should be provided by the module, not the component
})
export class AppComponent {
constructor(private authService: AuthenticationService, private router: Router) { }
login(): void {
this.authService.login().subscribe(data => {
alert(data);
this.router.navigate('/to-some-page');
});
}
}
More examples can be found with a simple Google search, like the one below https://coryrylan.com/blog/introduction-to-angular-routing
As far as I can see you are never directing the user to a steam page. Your comment to klong: "Redirection is done through Passport's". This might be, however you are never sending you user to a specific page. You are simply making a GET request form you frontend.
About the Same-origin policy error. I assume this is caused by Passport because you use Cors on your express server. I think the best solution would be to create a simple proxy. If you use the CLI you can use this example.
First of all, you do not send your login request to express backend. You must send your login request to steam oidc authorize endpoint. See what Steam says:
When using OpenID, the user begins in a web browser at the third-party website. When the user wishes to login/link their account to that website, using OpenID, the site directs the user to a login form on the Steam Community website. Once the user has entered their Steam login credentials, the user's web browser is automatically redirected back to the 3rd party website with some additional OpenID specific data appended to the return URL. The site's OpenID library can then use this data to verify and obtain the user's SteamID.
It is called Oidc and lucky you there's two good libraries for Angular. This (Recommended) and This.
What your express server need to do is validate the token recieved from your angular client before request. I'm not very familiar with express but, I'm sure there is at least a couple of libraries for you to validate token.
Also you need to do more research on this topic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With