I want to use a guard for my routes controller based on the access token of google, but I don't know how to implement this.
I retrieve this from my google oauth
{
"message": "User information from google",
"user": {
"email": "test#gmail.com",
"firstName": "John",
"lastName": "Kennedy",
"picture":
"https://lh3.googleusercontent.com/a-/mypicture",
"accessToken": "myaccesstoken"
}
}
Now I don't know how to use this access token for my other routes, example in a controller:
#UseGuards() // I don't know what to put here
#Get('/get_customer/:id')
async findCustomerById(#Param() params): Promise<Customer> {
try {
return await this.stripeService.findCustomerById(params.id);
} catch (e) {
throw new Error(e.message);
}
}
Short Answer:
Inside google's redirect endpoint, You can issue a JWT token to the user, which will hold their data as payload, and secure your endpoints with JWT verification guard.
See this
Long Answer:
What google basically does is just provide your application with the identity of the user who used that service to log in... Specifically, google provides you with the user's data(with the scopes you defined) and an access token.
at this point, you have multiple approaches to guard your routes:
Issue a JWT token that holds this user data you got from google and return it to the user(the client), each request the user sends with that token you would be able to identify the user and give them access to routes (stateless way: the token will hold everything encrypted inside it) See this.
Store a session of this user that contains the data you got from google, and give them the SessionId that will make you(the server) identify the user later on and give them access to routes (stateful way: you need to store the session data somewhere).
You might wonder what is the use of the access token in all of this... generally, this token can only be used by your application (which has ClientId+ClientSecret you got from google) to access user's google data(defined by scopes you chose) on behalf of them. So basically this token is a consent from the user so your app can access their google data.
This, for example, can be useful if you can't store user's data in our database(for legal reasons), so you can directly query their data from google without consulting them every single time.
Related
Hey im implementing authentication using NodeJS expressJS mongoDB / React native
is it okay to have a lot of variables in the token object like this example ?
const token = jwt.sign(
{
userId: user._id,
isAdmin: user.isAdmin,
isBanned:user.banned.isBanned
},
process.env.TOKEN_KEY,
{
expiresIn: "24H",
}
);
I added the isBanned one so i can check for it directly when the token goes to the frontend so i won't have to fetch for the user data again to get it !
Is this the best way to check if the user is banned ?
and Finally is it okay to put up to 3 variables on the token
For security reasons, it's not safe to store users datas in a JSON Web Token.
Typically you should only store the minimum datas needed to identify your user, meannig an ID.
You should also, if possible, use an unpredictable ID because numeric IDs are predictable.
The best is to have an alphanumeric uniq ID.
If you need to get some extra information once you user login, you can easilly issue a request to your API to retrieve informations...
Don't forget that token is given to the client by the server after a successfull login to avoid authenticate user at each request, not for retrieving informations.
To provide dynamic content delivery, I am using rewrites in fire base hosting. Whenever open website with index.html then the browser request the firebase cloud function main.
"rewrites": [ {
"source": "/index.html",
"function":"main"
}]
Now I am facing a problem to provide dynamic content based on user login status. I also checked about client side authendication using JS.
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
I don't know about web development. Here I have few questions,
How can I find authentication status of user by more flexible way? Does cookies used for this? I am asking because I don't know to pass firebase-token to the cloud function main.
Please address me an idea. Thank you all.
Short answer: End users don't have a sign-in status that's visible on a backend. That's just not how Firebase Authentication works.
Auth clients provide credentials to get a token that's used to identify themself when they invoke backend services. This tokens has a lifetime of 1 hour, and the client must refresh it in order to keep using it. Your backend doesn't know or care if the client has an auth token, if they use it, or if they refresh it. The client just needs to provide that token from whatever device they have signed in so the backend can validate it. There is no way your backend can know if the client obtained a token - you just have to accept the one it is given. This means you're going to have to actually figure out how to pass that token and validate it with the Firebase Admin SDK, or use a callable type function using the Firebase Client SDK to send that token automatically.
I'm trying to keep things simple and using auth0-js WebAuth to authenticate users. However, as there is a redirect involved, I'm not in control of the sign-up functionality at that point.
My specific use-case is to call a createUser graphql mutation using Graphcool to create a user in my database, but I only want to do this if the user is a new user, obviously.
MY QUESTION: Using auth0-js, is it possible to identify if a user is a new or existing user in my client application after the redirect from Auth0 back to my client application (assuming authentication is successful)?
There are two general approaches here, and both require you to persist the Auth0 token in local storage after receiving it. You can use a middleware for your GraphQL client that checks local storage for a token for every request and includes it as the Authorization: Bearer <token> header if present.
Let's now look at the two approaches.
Always try to create the user
Trying to create the user using the createUser mutation as soon as receiving the token is a fairly simple approach. This is how the mutation looks like:
mutation signUp($token: String!) {
createUser(authProvider: {
auth0: {
idToken: $token
}
}) {
id
}
}
Now, if the token is valid and matches the configuration of the Auth0 integration in Graphcool, there are two possible scenarios. Note, a token corresponds to a user if the auth0UserId it embeds matches.
there is already a registered user corresponding to the token. In this case, a GraphQL error Code 3023: CannotSignUpUserWithCredentialsExist will be returned (compare with the error reference documentation). In your application you can catch this error to proceed normally.
there is no registered user yet corresponding to the token. The createUser mutation will return id and all is good!
Check if the user is already signed in
If you have a more elaborate sign up flow, you might want to redirect your users to a sign up form, which is not really possible with the first approach. Instead, we can check if the currently used token corresponds to a registered user before proceeding. You can use the user query to do that:
query {
user {
id
}
}
Again, there are the same two scenarios as above:
there is already a registered user corresponding to the token. In this case, a the query returns a user object with the corresponding user id. So we can proceed the flow in the app normally.
there is no registered user yet corresponding to the token. The date returned from the user query will be null, so we need to call the createUser mutation, or switch to a sign up form or similar.
Compare this to this FAQ article in the Graphcool documentation.
In that case, the simplest solution will be to use auth0 rule and use context.stats.loginsCount field to detect the user is new or not.
https://auth0.com/docs/rules/references/context-object
You can add context.stats.loginsCount field value as a custom claim in the token using rule. Therefore, in your application, you can make a HTTP request to /userinfo endpoint to get the token data.
function (user, context, callback) {
const count=context.stats.loginsCount;
context.idToken["http://mynamespace/logincounts"] = count;
callback(null, user, context);
}
https://auth0.com/docs/api-auth/tutorials/adoption/scope-custom-claims
If the counts are equal to 1, create the user in your DB.
In order to get token i post following request:
http://example.com/wordpress/wp-json/jwt-auth/v1/token?username=MYLOGIN&password=MYPASSWORD and in response i get token - that's nice, but... what if i don't want to show username and login in requested URL, even a single time.
Everyone who can see my computer requests can catch my login and password easily. Can I somehow hide this sensitive data in request headers instead of url parameters? I'm using "Chrome Insomnia" App to test REST api and next to PARAMS and HEADERS there is an AUTH tab where i can type username and password - maybe that is the place i could use to send user data to get access token without beeing seen easily?
I tried to login using AUTH tab, but in response:
{
"code": "jwt_auth_bad_auth_header",
"message": "Authorization header malformed.",
"data": {
"status": 403
}
}
Please don't send me back to wp-api documentaion because i couldn't find a clear answer by reading the docs there.
Use OAuth.
It is a secure way to authorize yourself on a REST-Api without having to send your username and password as plain text.
The WP-API documentation has a section called OAuth Authentication. The API uses OAuth 1.0. Basically you have to install the OAuth-Plugin, then generate a Client which automatically gets a Key and a Secret assigned. You can use this pair for a secure authentification.
You can find more detailed information in the link I gave above, it is fairly simple to implement.
To answer your original question on how you can keep people from seeing your passwords in Insomnia, it is recommended that you put sensitive data in an environment variable and reference it in your request.
You can define your environment JSON like this...
{
"username": "MyUsername",
"password": "MyPassword"
}
And reference them in the params tab (or anywhere else) using Nunjucks template syntax like {{ username }} and {{ password }}.
Here's a link to the docs on Environment Variables inside Insomnia.
~ Gregory
Although I agree OAuth (Really OpenID Connect) is a better solution,
USE HTTPS.
Since the SSL/TLS is performed before you make the request, it will be encrypted over the network.
Can I access Google Analytics data using a service account in a client-side application? If not, are there other ways of achieving the same outcome?
Must be entirely client-side, and must not require users to authenticate (hence the desire to use a service account).
Yes you can in https://code.google.com/apis/console make sure you say that its a Service account it will give you a key file to download. With that you dont need a user to click ok to give you access.
For a service acccount to work you need to have a key file. Anyone that has access to that key file will then be able to access your Analytics data. Javascript is client sided which means you will need to send the key file. See the Problem? You are handing everyone access to your account. Even if you could get a service account to work using javascript for security reasons its probably not a very good idea.
You can use the official (and alpha) Google API for Node.js to generate the token. It's helpful if you have a service account.
On the server:
npm install -S googleapis
ES6:
import google from 'googleapis'
import googleServiceAccountKey from '/path/to/private/google-service-account-private-key.json' // see docs on how to generate a service account
const googleJWTClient = new google.auth.JWT(
googleServiceAccountKey.client_email,
null,
googleServiceAccountKey.private_key,
['https://www.googleapis.com/auth/analytics.readonly'], // You may need to specify scopes other than analytics
null,
)
googleJWTClient.authorize((error, access_token) => {
if (error) {
return console.error("Couldn't get access token", e)
}
// ... access_token ready to use to fetch data and return to client
// even serve access_token back to client for use in `gapi.analytics.auth.authorize`
})
If you went the "pass the access_token back to client" route:
gapi.analytics.auth.authorize({
'serverAuth': {
access_token // received from server, through Ajax request
}
})