How to set scope(or role) of nuxt $auth.user? - vue.js

I am using nuxt-auth with google oauth2 config, here is my nuxt.config.js config:
auth: {
scopeKey: 'scope',
strategies: {
google: {
client_id: process.env.GOOGLE_KEY,
codeChallengeMethod: '',
scope: ['profile', 'email'],
responseType: 'token id_token'
}
},
redirect: {
login: '/login',
logout: '/logout',
home: '/',
callback: '/welcome'
}
},
router: {
middleware: ['auth']
},
I use this code to login
this.$auth.loginWith('google')
I want to setup a role for user (visit app database) after successful login, so I added this code to my welcome.vue (oauth2 callback page)
<script>
export default {
mounted () {
const user = this.$auth.user
user['scope'] = 'some_role_from_db'
this.$auth.setUser(user)
}
}
</script>
but this code is never called, because application is immediately redirected to the page that user has selected before visiting login page (welcome.vue html markup is shown for 1 sec).
What is the correct way to set some attributes to this.$auth.user immediately after login? Is there some easy way to set role to user after OAUTH2 authentication?

user roles must came from server and it wrong to define it from client side ,
but if that is importent you can do it like that :
this.$auth.loginWith('google').then(() => {
const user = this.$auth.user
user['scope'] = 'some_role_from_db'
this.$auth.setUser(user)
})

I've added this section to my auth object in nuxt.config.js
rewriteRedirects: false
and so my app always redirects me to home url, and on home page I can access auth object like
<script>
export default {
mounted () {
const user = this.$auth.user
user['scope'] = 'some_role_from_db'
this.$auth.setUser(user)
}
}
</script>

Related

Nuxt 3 JWT authentication using $fetch and Pinia

I'm discovering Nuxt 3 since a few days and I'm trying to do a JWT authentication to a distinct API.
As #nuxtjs/auth-next doesn't seem to be up to date and as I read it was possible to use the new global method fetch in Nuxt 3 instead of #nuxtjs/axios (not up to date also), I thought it won't be too hard to code the authentication myself! But it stays a mystery to me and I only found documentation on Vue project (using Pinia to keep user logged in) and I'm a bit at a lost.
What I would like to achieve:
a login page with email and password, login request send to API (edit: done!)
get JWT token and user info from API (edit: done!) and store both (to keep user logged even if a page is refresh)
set the JWT token globally to header $fetch requests (?) so I don't have to add it to each request
don't allow access to other pages if user is not logged in
Then I reckon I'll have to tackle the refresh token subject, but one step at a time!
It will be really awesome to have some help on this, I'm not a beginner but neither a senior and authentication stuff still frightens me :D
Here is my login.vue page (I'll have to use Vuetify and vee-validate after that but again one step at a time!)
// pages/login.vue
<script setup lang="ts">
import { useAuthStore } from "~/store/auth";
const authStore = useAuthStore();
interface loginForm {
email: string;
password: string;
}
let loginForm: loginForm = {
email: "",
password: "",
};
function login() {
authStore.login(loginForm);
}
</script>
<template>
<v-container>
<form #submit.prevent="login">
<label>E-mail</label>
<input v-model="loginForm.email" required type="email" />
<label>Password</label>
<input v-model="loginForm.password" required type="password" />
<button type="submit">Login</button>
</form>
</v-container>
</template>
The store/auth.ts for now.
// store/auth.ts
import { defineStore } from 'pinia'
import { encodeURL } from '~~/services/utils/functions'
export const useAuthStore = defineStore({
id: 'auth,
state: () => ({
// TODO Initialize state from local storage to enable user to stay logged in
user: '',
token: '',
})
actions: {
async login(loginForm) {
const URL_ENCODED_FORM = encodeURL({
email: loginForm.email,
password: loginForm.password,
});
return await $fetch('api_route', {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: 'POST',
body: URL_ENCODED_FORM
}
}
}
})
i'm gonna share everything, even the parts you marked as done, for completeness sake.
Firstly, you will need something to generate a JWT in the backend, you can do that plainly without any packages, but i would recommend this package for that. Also i'll use objection.js for querying the database, should be easy to understand even if you don't know objection.js
Your login view needs to send a request for the login attempt like this
const token = await $fetch('/api/login', {
method: 'post',
body: {
username: this.username,
password: this.password,
},
});
in my case it requests login.post.ts in /server/api/
import jwt from 'jsonwebtoken';
import { User } from '../models';
export default defineEventHandler(async (event) => {
const body = await useBody(event);
const { id } = await User.query().findOne('username', body.username);
const token: string = await jwt.sign({ id }, 'mysecrettoken');
return token;
});
For the sake of simplicity i didn't query for a password here, this depends on how you generate a user password.
'mysecrettoken' is a token that your users should never get to know, because they could login as everybody else. of course this string can be any string you want, the longer the better.
now your user gets a token as the response, should just be a simple string. i'll write later on how to save this one for future requests.
To make authenticated requests with this token you will need to do requests like this:
$fetch('/api/getauthuser', {
method: 'post',
headers: {
authentication: myJsonWebToken,
},
});
i prefer to add a middleware for accessing the authenticated user in my api endpoints easier. this middleware is named setAuth.ts and is inside the server/middleware folder. it looks like this:
import jwt from 'jsonwebtoken';
export default defineEventHandler(async (event) => {
if (event.req.headers.authentication) {
event.context.auth = { id: await jwt.verify(event.req.headers.authentication, 'mysecrettoken').id };
}
});
What this does is verify that if an authentication header was passed, it checks if the token is valid (with the same secret token you signed the jwt with) and if it is valid, add the userId to the request context for easier endpoint access.
now, in my server/api/getauthuser.ts endpoint in can get the auth user like this
import { User } from '../models';
export default defineEventHandler(async (event) => {
return await User.query().findById(event.context.auth.id)
});
since users can't set the requests context, you can be sure your middleware set this auth.id
you have your basic authentication now.
The token we generated has unlimited lifetime, this might not be a good idea. if this token gets exposed to other people, they have your login indefinitely, explaining further would be out of the scope of this answer tho.
you can save your auth token in the localStorage to access it again on the next pageload. some people consider this a bad practice and prefer cookies to store this. i'll keep it simple and use the localStorage tho.
now for the part that users shouldnt access pages other than login: i set a global middleware in middleware/auth.global.ts (you can also do one that isnt global and specify it for specific pages)
auth.global.ts looks like this:
import { useAuthStore } from '../stores';
export default defineNuxtRouteMiddleware(async (to) => {
const authStore = useAuthStore();
if (to.name !== 'Login' && !localStorage.getItem('auth-token')) {
return navigateTo('/login');
} else if (to.name !== 'Login' && !authStore.user) {
authStore.setAuthUser(await $fetch('/api/getauthuser', {
headers: authHeader,
}));
}
});
I'm using pinia to store the auth user in my authStore, but only if the localstorage has an auth-token (jwt) in it. if it has one and it hasnt been fetched yet, fetch the auth user through the getauthuser endpoint. if it doesnt have an authtoken and the page is not the login page, redirect the user to it
With the help of #Nais_One I managed to do a manual authentication to a third-party API with Nuxt 3 app using client-side rendering (ssr: false, target: 'static' in nuxt.config.ts)
I still have to set the API URL somewhere else and to handle JWT token refresh but the authentication works, as well as getting data from a protected API route with the token in header and redirection when user is not logged.
Here are my finals files:
// pages/login.vue
<script setup lang="ts">
import { useAuthStore } from "~/store/auth";
const authStore = useAuthStore();
const router = useRouter();
interface loginForm {
email: string;
password: string;
}
let loginForm: loginForm = {
email: "",
password: "",
};
/**
* If success: redirect to home page
* Else display alert error
*/
function login() {
authStore
.login(loginForm)
.then((_response) => router.push("/"))
.catch((error) => console.log("API error", error));
}
</script>
<template>
<v-container>
<form #submit.prevent="login">
<label>E-mail</label>
<input v-model="loginForm.email" required type="email" />
<label>Password</label>
<input v-model="loginForm.password" required type="password" />
<button type="submit">Login</button>
</form>
</v-container>
</template>
For the auth store:
// store/auth.ts
import { defineStore } from 'pinia'
const baseUrl = 'API_URL'
export const useAuthStore = defineStore({
id: 'auth',
state: () => ({
/* Initialize state from local storage to enable user to stay logged in */
user: JSON.parse(localStorage.getItem('user')),
token: JSON.parse(localStorage.getItem('token')),
}),
actions: {
async login(loginForm) {
await $fetch(`${baseUrl}/login`, {
method: 'POST',
body: loginForm
})
.then(response => {
/* Update Pinia state */
this.user = response
this.token = this.user.jwt_token
/* Store user in local storage to keep them logged in between page refreshes */
localStorage.setItem('user', JSON.stringify(this.user))
localStorage.setItem('token', JSON.stringify(this.token))
})
.catch(error => { throw error })
},
logout() {
this.user = null
this.token = null
localStorage.removeItem('user')
localStorage.removeItem('token')
}
}
})
I also use the middleware/auth.global.ts proposed by Nais_One.
And this fetch-wrapper exemple I found here as well to avoid having to add token to every requests: https://jasonwatmore.com/post/2022/05/26/vue-3-pinia-jwt-authentication-tutorial-example and it seems to work perfectly. (I just didn't test yet the handleResponse() method).
Hope it can help others :)
That temporary alternative https://www.npmjs.com/package/#nuxtjs-alt/auth is up to date
And that https://www.npmjs.com/package/nuxtjs-custom-auth and https://www.npmjs.com/package/nuxtjs-custom-http work with Nuxt 3 $fetch and no need to use axios
Recently a new package was released that wraps NextAuth for Nuxt3. This means that it already supports many providers out of the box and may be a good alternative to look into.
You can install it via:
npm i -D #sidebase/nuxt-auth
Then it is pretty simple to add to your projects as you only need to include the module:
export default defineNuxtConfig({
modules: ['#sidebase/nuxt-auth'],
})
And configure at least one provider (like this example with Github):
import GithubProvider from 'next-auth/providers/github'
export default defineNuxtConfig({
modules: ['#sidebase/nuxt-auth'],
auth: {
nextAuth: {
options: {
providers: [GithubProvider({ clientId: 'enter-your-client-id-here', clientSecret: 'enter-your-client-secret-here' })]
}
}
}
})
Afterwards you can then get access to all the user data and signin/signup functions!
If you want to have a look at how this package can be used in a "real world" example, look at the demo repo in which it has been fully integrated:
https://github.com/sidebase/nuxt-auth-example
I hope this package may be of help to you and others!
Stumbling on the same issue for a personal project and what I do is declare a composable importing my authStore which is basically a wrapper over $fetch
Still a newb on Nuxt3 and Vue but it seems to work fine on development, still have to try and deploy it though
import { useAuthStore } from "../store/useAuthStore";
export const authFetch = (url: string, opts?: any | undefined | null) => {
const { jwt } = useAuthStore();
return $fetch(url, {
...(opts ? opts : {}),
headers: {
Authorization:`Bearer ${jwt}`,
},
});
};
And then I can just use it in my actions or components
// #/store/myStore.ts
export const useMyStore = defineStore('myStore', () => {
async getSomething() {
...
return authFetch('/api/something')
}
})
// #components/myComponent.vue
...
<script setup lang="ts">
const handleSomething = () => {
...
authFetch('/api/something')
}
</script>
Hope it helps someone !

How to show login page by default after logout?

I want to show my login screen after logout.
Currently without LogoutModule after logout my page is redirecting to a blank screen and if I implement it as per the documentation, it redirects to homepage.
Documentation reference: https://sap.github.io/spartacus/modules/LogoutModule.html
#NgModule({
imports: [
PageLayoutModule,
RouterModule.forChild([
{
path: null,
canActivate: [LogoutGuard, CmsPageGuard],
component: PageLayoutComponent,
data: { cxRoute: 'logout' },
},
]),
],
})
I have tried protecting my homepage, however if I do that, I am unable to logout at all i.e. nothing is happening if I click logout.
You can achieve this by overriding the default getRedirectUrl from LogoutGuard.
Currently, the base class redirects to login page upon logout if and only if it's a closed shop. Meaning, the user must login before doing any action (early login).
An example of how to override the LogoutGuard behavior is to do the following:
1 - create your custom logout guard
#Injectable({
providedIn: 'root',
})
export class NewLogoutGuard extends LogoutGuard {
constructor(
auth: AuthService,
cms: CmsService,
semanticPathService: SemanticPathService,
protectedRoutes: ProtectedRoutesService,
router: Router,
authRedirectService: AuthRedirectService
) {
super(
auth,
cms,
semanticPathService,
protectedRoutes,
router,
authRedirectService
);
}
protected getRedirectUrl(): UrlTree {
return this.router.parseUrl(this.semanticPathService.get('login'));
}
}
2 - aliasing the class providers by providing the new logout guard
{ provide: LogoutGuard, useExisting: NewLogoutGuard },

$auth object is empty eventhough my nuxt app is logged in

I'm very new to both nuxt and auth0. I'm using auth0 with my nuxt app and I have written a piece of code in my main pages mounted hook that enables me to login to the server when I use $auth.login() then it returns me to my app and gives me a token in the url. I can get my user profile's info using the token with /auth/me in my mounted hook but when I log $auth.$state it says you're not logged in:
loggedIn: false
strategy: "auth0"
user: null
How can I use $auth object with my auth0 code?
This is my nuxt.config.js:
auth: {
redirect: {
login: '/',
callback: '/auth/signed-in'
},
strategies: {
local: false,
auth0: {
domain: process.env.AUTH0_DOMAIN,
client_id: process.env.AUTH0_CLIENT_ID,
}
}
},

How do I automatically redirect the user if they are already logged in using Vue and Firebase authentication?

Description
I am trying to automatically route the user to the "Games.vue" component if they are already logged in. For authentication I am using Firebase and I check if they are logged in using:
var user = firebase.auth().currentUser;
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
What I want to have happen is for the user to not see the Login page if they are already signed in. So they are taken directly to the Games page. I don't know how to accomplish this using Vue. I need something to run before the Login-component that redirects if logged in.
Attempt at solution
The only way I know how to solve this is to show the Login page, check if the Firebase user is logged in and then go to the Games page. This can work, but it isn't the behavior I am looking for. I am using the Vue router. Thank you for your help.
I would suggest to use a VueRouter global guard like so:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
if (!user) {
next('login');
} else {
next();
}
})
That being said, you then need a way to specify which route requires authentication. I would suggest to use route meta fields like so:
routes = [
{
name: 'login',
path: '/login',
meta: {
requiresAuth: false
}
},
{
name: 'games',
path: '/games',
meta: {
requiresAuth: true
}
}
]
Now your guards becomes:
if (!user && to.meta.requiresAuth) {
next('login');
} else {
next();
}
Vue router provides an example for this use case, take a look at the documentation.
TIP: Make sure to subscribe to auth changes using Firebase onAuthStateChanged method.
let user = firebase.auth().currentUser;
firebase.auth().onAuthStateChanged(function(user) {
user = user;
});
EDIT: To redirect once logged in, just watch for auth changes and redirect using router.push.
auth.onAuthStateChanged(newUserState => {
user = newUserState;
if (user) {
router.push("/games");
}
});

multiple login routes using ember-cli-simple-auth

I am trying to configure a basic ember-cli app using authentication via ember-cli-simple-auth and want to have a dedicated 'guest' login page and a different 'admin' login page (authorizing to different serverTokenEnpoint's).
I have the 'guest' page working, i.e. if a user tries to browse to a protected route (page) then they are redirected to the default /login route and can login Ok.
What I can't figure out is how to have a user that browse's to /admin/xyz route that they then get redirected (using to /admin/login which in turn will authenticate to a different serverTokenEnpoint to the default.
Can anyone point me in the right direction to achieve the above?
Thanks.
an example protected 'guest' route file looks like:
FILE: /app/routes/protected.js
import Ember from 'ember';
import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin);
And the environment configs contain:
FILE: /app/config/environment.js
ENV['simple-auth'] = {
authorizer: 'simple-auth-authorizer:oauth2-bearer',
store: 'simple-auth-session-store:local-storage',
crossOriginWhitelist: ['http://www.domain.com/token',
'http://www.domain.com'
]
};
I even tried to override the default authenticationRoute in my /app/routes/admin.js file like below but did not work:
import Ember from 'ember';
import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin,{
authenticationRoute: 'admin.login'
});
So to simplify the process following Marco's suggestion I now have:
Note: AT the moment this does not work.. #marcoow do you have any thoughts where im going wrong?
This is using ember-cli with the follow firebug output:
AuthenticatorBase A (unknown mixin) ***<- IS this expected????***
CustomAuthenticator B (unknown mixin)
DEBUG: -------------------------------
DEBUG: Ember : 1.7.0
DEBUG: Ember Data : 1.0.0-beta.9
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 1.11.1
DEBUG: Ember Simple Auth : 0.6.4
DEBUG: Ember Simple Auth OAuth 2.0 : 0.6.4
DEBUG: -------------------------------
and if I put my manual override code back in see previous answer it will work, but since I want to use the same oauth2 authentication just to a different URL, I like the idea of just being able to override the TokenEndpoint with a custom authenticator.
file: app/initializers/simple-auth-admin.js
import AuthenticatorBase from 'simple-auth-oauth2/authenticators/oauth2';
var CustomAuthenticator = AuthenticatorBase.extend({
serverTokenEndpoint: AppchatENV['simple-auth-admin'].serverTokenEndpoint,
serverTokenRevokationEndpoint: AppchatENV['simple-auth-admin'].serverRevokationTokenEndpoint,
refreshAccessTokens: AppchatENV['simple-auth-admin'].refreshAccessTokens
});
console.log("AuthenticatorBase A ",AuthenticatorBase);
console.log("CustomAuthenticator B ",CustomAuthenticator);
export default {
name: 'simple-auth-admin',
before: 'simple-auth',
initialize: function(container) {
container.register('simple-auth-authenticator:admin', CustomAuthenticator);
}
};
But the above shows an error of "AuthenticatorBase A (unknown mixin)"
and then in
file: app/controllers/admin/login.js
import Ember from 'ember';
import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin';
export default Ember.Controller.extend(LoginControllerMixin, {
authenticator: 'simple-auth-authenticator:admin'
}
and for the configs...
file: config/environment.js
ENV['simple-auth-admin'] = {
serverTokenEndpoint: "http://www.domain.com/admintoken",
serverTokenRevokationEndpoint: "http://www.domain.com/admintoken/revoke",
refreshAccessTokens: true
};
EDIT:
so by setting: in file: app/initializers/simple-auth-admin.js
import AuthenticatorBase from 'simple-auth-oauth2/authenticators/oauth2';
var CustomAuthenticator = AuthenticatorBase.extend({
serverTokenEndpoint: MyappENV['simple-auth-admin'].serverTokenEndpoint,
serverTokenRevokationEndpoint: MyappENV['simple-auth-admin'].serverRevokationTokenEndpoint,
refreshAccessTokens: MyappENV['simple-auth-admin'].refreshAccessTokens
});
console.log("AuthenticatorBase.serverTokenEndpoint =",AuthenticatorBase.serverTokenEndpoint);
console.log("CustomAuthenticator.serverTokenEndpoint =",CustomAuthenticator.serverTokenEndpoint);
console.log("MyappENV['simple-auth-admin'].serverTokenEndpoint = ",MyappENV['simple-auth-admin'].serverTokenEndpoint);
export default {
name: 'simple-auth-admin',
before: 'simple-auth',
initialize: function(container) {
container.register('simple-auth-authenticator:admin', CustomAuthenticator);
console.log("[at container.register] CustomAuthenticator.serverTokenEndpoint = ",CustomAuthenticator.create().get('serverTokenEndpoint'));
}
};
I get output of:
AuthenticatorBase.serverTokenEndpoint = undefined
CustomAuthenticator.serverTokenEndpoint = undefined
MyappENV['simple-auth-admin'].serverTokenEndpoint = http://www.domain.com/oauth2/admintoken
[at container.register] CustomAuthenticator.serverTokenEndpoint = http://www.domain.com/oauth2/admintoken
Am I misuderstanding what AuthenticatorBase.extend () is doing? I thought it would allow you to override some variables or functions?
EDIT 2:
file: app/controllers/admin/login.js
import Ember from 'ember';
var $ = Ember.$;
import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin';
export default Ember.Controller.extend(LoginControllerMixin, {
authenticator: 'simple-auth-authenticator:admin',
init: function(){
console.log('INIT LOGIN CONTROLLER', this.get('session'));
this._super();
},
actions: {
authenticate: function() { // (data)
console.log("LoginController clicked");
$('#nameBtn').ladda().ladda('start');
console.log(this.get('session'));
console.log('this.authenticator = ', this.authenticator);
var _this = this;
this._super().then(null, function(data) {
console.log('LOGIN GOT BACK: ', data);
$('#nameBtn').ladda().ladda('stop');
if(data.error !== undefined && data.error !== "") {
_this.set('data', {error: data.error});
}
});
}
}
});
This results in an ajax to www.domain.com/token rather than the expected www.domain.com/admintoken
OK, after a lot of coding in circles and trial and error and with a lot of help from:
https://github.com/simplabs/ember-simple-auth/blob/master/examples/6-custom-server.html
this is how I achieved what I wanted...
1) Setup the enpoints as variables in the environment file (simple-auth-admin is the name i chose for my admin authenticator)
File: /app/config/environment.js
ENV['simple-auth-admin'] = {
serverTokenEndpoint: "http://www.domain.com/admintoken",
serverTokenRevokationEndpoint: "http://www.domain.com/admintoken/revoke",
refreshAccessTokens: true
};
2) Create the actual authenticator as an override in an initialiser Note: in this case the CustomAuthorizer is not actually used and make sure you replace AppNameENV with your app name, so if your app was called bob it would be BobENV.
File: /app/initializers/simple-auth-admin.js
import Ember from 'ember';
import AuthenticatorBase from 'simple-auth/authenticators/base';
import AuthorizerBase from 'simple-auth/authorizers/base';
var CustomAuthorizer = AuthorizerBase.extend({
authorize: function(jqXHR, requestOptions) {
if (this.get('session.isAuthenticated') && !Ember.isEmpty(this.get('session.token'))) {
jqXHR.setRequestHeader('Authorization', 'Token: ' + this.get('session.token'));
}
}
});
var CustomAuthenticator = AuthenticatorBase.extend({
tokenEndpoint: window.AppNameENV['simple-auth-admin'].serverTokenEndpoint,
tokenRevokationEndpoint: window.AppNameENV['simple-auth-admin'].serverRevokationTokenEndpoint,
refreshAccessTokens: window.AppNameENV['simple-auth-admin'].refreshAccessTokens,
init: function(){
console.log("CUSOTMM AUTH INIT ",window.AppNameENV['simple-auth-admin'].serverTokenEndpoint);
this._super();
},
restore: function(data) {
console.log('AdminAuth - restore');
return new Ember.RSVP.Promise(function(resolve, reject) {
if (!Ember.isEmpty(data.token)) {
resolve(data);
} else {
reject();
}
});
},
authenticate: function(credentials) {
console.log('AdminAuth - authenticate',credentials);
var _this = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
url: _this.tokenEndpoint,
type: 'POST',
data: JSON.stringify({ grant_type: 'password', username: credentials.identification, password: credentials.password, session: { identification: credentials.identification, password: credentials.password } }),
contentType: 'application/json'
}).then(function(response) {
Ember.run(function() {
resolve({ token: response.access_token });
});
}, function(xhr, status, error) {
var response = JSON.parse(xhr.responseText);
Ember.run(function() {
reject(response.error);
});
});
});
},
invalidate: function() {
console.log('AdminAuth - invalidate');
var _this = this;
return new Ember.RSVP.Promise(function(resolve) {
Ember.$.ajax({ url: _this.tokenEndpoint, type: 'DELETE' }).always(function() {
resolve();
})
});
}
});
export default {
name: 'simple-auth-admin',
before: 'simple-auth',
initialize: function(container) {
console.log("OVERRIDES : ", window.AppNameENV['simple-auth-admin']);
container.register('simple-auth-authenticator:admin', CustomAuthenticator);
container.register('simple-auth-authorizer:admin', CustomAuthorizer);
}
};
3) The I setup a redirect route to admin/login for any protected pages ( this example is for /admin/dashboard)
File: /app/routes/admin/dashboard.js
import Ember from 'ember';
import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin,{
authenticationRoute: 'admin.login',
actions: {
authenticateSession: function() {
this.transitionTo(this.authenticationRoute);
}
}
});
4) Then configure the admin controller to use the new custom authenticator
File: /app/controllers/admin/login.js
import Ember from 'ember';
var $ = Ember.$;
import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin';
//import Session from 'simple-auth/session';
export default Ember.Controller.extend(LoginControllerMixin, {
authenticator: 'simple-auth-authenticator:admin',
});
All of which seems a bit heavy handed when all i really wanted to do was have the authentication for the /admin/login point to a different serverendpoint. Marco, is there a way of overriding just those variables and therefore extend the simple-auth-oauth2 authorizer?
The routes you're defining are necessary of course.
Since your authorizer and authenticator for the admin area seem to be customized as well those are necessary as well of course. If you used the plain OAuth 2.0 ones for the admin area as well you could drop the authorizer and change the authenticator to
import AuthenticatorBase from 'simple-auth-oauth2/authenticators/oauth2';
var CustomAuthenticator = AuthenticatorBase.extend({
serverTokenEndpoint: 'http://www.domain.com/admintoken',
serverTokenRevokationEndpoint: 'http://www.domain.com/admintoken/revoke'
});
Every time Ember Simple Auth enforces authentication (usually when a user accesses an authenticated route while the session is not authenticated), it calls the ApplicationRouteMixin's authenticateSession action. The best option you have is to override that and somehow decide whether to transition to the admin or the guest login page from there. If you have e.g. your admin pages namespaces in an /admin route, you could also override the authenticateSession on the AdminRoute and transition to the admin login page from there while the default implementation in the ApplicationRoute transitions to the guest login page.
For the authenticators it's probably best to use the default OAuth 2.0 authenticator with its serverTokenEndpoint to authenticate guests and extend another authenticator from that that authenticates admin against a different serverTokenEndpoint.