What is the first parameter for Firebase.Auth.GoogleAuthProvider.GetCredential? - authentication

The new Firebase for Unity support has just been released into Beta and I am trying to implement Auth with it. I already have a Google sign-in that implements the oauth2 flow using an auth code from GooglePlayGames.PlayGamesPlatform.Instance.GetServerAuthCode and sending it to a server that exchanges it for an access token using the https://www.googleapis.com/oauth2/v4/token endpoint.
I assume this access token is the second parameter of the Firebase.Auth.GoogleAuthProvider.GetCredential method, but what is the ID Token that the first parameter is asking for? Is that the token obtained from GooglePlayGames.PlayGamesPlatform.Instance.GetIdToken (same as GoogleAuthUtil.GetToken, if my reading of the docs/code is correct)?
If this is the case, why are both required? I thought the access token was all that was needed to authenticate a user with google cloud services and that the ID Token was being phased out.
Edit: After some testing, I found that passing the ID Token obtained from GooglePlayGames.PlayGamesPlatform.Instance.GetIdToken does allow Firebase to authenticate. Problem is, it asks for the user's email address every time. I'd like to avoid this if possible.
What is the difference between GetToken, GetAccessToken and GetIdToken, aside from the fact that GetIdToken requires a callback?

I managed to "hack" this in order to get it working... But still i think the correct method should only be using GetServerAuthCode but I cannot make it work with that.
Do your normal process of getting idToken and AccessToken the first time, when you log in to firebase get the user's email and store it in playerprefs. Then the second time if you already have the email you do this:
AndroidJavaClass authUtil = new AndroidJavaClass("com.google.android.gms.auth.GoogleAuthUtil");
AndroidJavaClass unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity");
string idToken = authUtil.CallStatic<string>("getToken", currentActivity, PlayerData.Email, "audience:server:client_id:XXXXXXXXXX-xxxxxxxxxxxxxx.apps.googleusercontent.com"); // your client id, should be a number a dash and then a bunch of numbers and letters
string accessToken = authUtil.CallStatic<string>("getToken", currentActivity, PlayerData.Email, "oauth2:https://www.googleapis.com/auth/plus.me");
Hope it helps although it would be greatif someone posts a solution with GetServerAuthCode cause that is the correct way

Related

best practices for refreshing access tokens automatically

I'm building a react native app which uses the spotify web api. I'm using the authorization code flow to authorize a user. First I get a authorization code which can be used to obtain an access token and a refresh token. Everything works!
The problem is: an access token is only valid for a limited amount of time. That's where the refresh token comes in. I understand this concept, but I'm breaking my head about how to implement this.
Let's say a users opens the app, requests an access token and uses this for some time. Then, the user closes the app. After 15 minutes, the users opens the app again. The access token has now expired, so I need to request a new access token.
I've come op with several "solutions". Can someone point me to the correct solution?
Solution 1:
Every time the user opens the app, I request a new access token and use this. Problem: when the user uses the app longer than the valid time of the access token, I won't work anymore.
Solution 2:
I use the access token that's stored in the secure storage on every request. When a request comes back with 'access token invalid' (I don't know the exact error code but you guys know what I mean), I request a new access token with the stored refresh token, and then I send the previous command again (with the new access token). But my question here is: can I use some kind of "wrapper function" which checks the response of the request, and if the response is "access token invalid", it automatically requests a new access token and runs the previous request again.
I think certainly correct solution is solution 2,and i think its clear enough.
and for using solution 2 you need somthing like wrapper function,yes its intelligently.
so you should use interceptor:
what is interceptor ?
You can intercept requests or responses before they are handled by then or catch.
in link below there is a good example of implementing refresh token in axios interceptor:
https://gist.github.com/Godofbrowser/bf118322301af3fc334437c683887c5f
I agree that Solution 2 is the best, each time you do a request you can check to see if the Access Token has expired, and if it has then you can request a new Access Token using the Refresh Token as you mentioned and then make your request, in my own project I do this in a FormatRequestHeadersAsync method which calls a CheckAndRenewTokenAsync method where I perform the following check, here shown in C#:
if(AccessToken?.Refresh != null && (AccessToken.Expiration < DateTime.UtcNow))
{
AccessToken = await GetRefreshTokenAsync(
AccessToken.Refresh,
AccessToken.TokenType,
cancellationToken);
}
You can store the Access Token and the Refresh Token and then use something similar to this before you make each request to the API this will refresh your token and then you can store the new Access Token and the existing Refresh Token.

Amplify federated saml sign in not authenticated

So I'm not quite understanding why this isn't working. Some background; We have a SAML identity provider in our user pool, its a registered identity in our identity pool as well which i see when i go to dashboard. I am pretty frustrated form the lack of central documentation for Amplify, it's incredibly difficult to find anything online and I just keep trying things I see and they don't work.
What I already have:
I already have it working in the sense that I get an access_token back from the SAML provider, and that all works fine. So I know it's working fine (the login part), but the issue I am having is basically updating Amplify to now have the user in session so we can take advantage of functionality within Amplify that lets you refresh tokens when they expire.
Essentially, this is the flow I am using, from different sources I've found online:
await Auth.federatedSignIn({ provider });
this line of code can either be google, facebook or our custom SAML one we made. I already know this works, bc again, I already get my access token. So now, this is where my confusion starts. Obviously this function call here will take the user away from the page, hence we cant await this call, or i mean, you can, but it wont return the user on page reload. Which is fine, that part makes sense. So I have a function when the component is loaded that checks to see if theres a access_token in the url hash, which works as well.
Now, the issue is, Amplify doesn't know we signed in. We have "logged in" in the sense that yes, we have a valid JWT token now from the url hash access_token but the local Amplify does not know that this user is logged in.
So this is what I am talking about with the lack of documentation, perhaps I am crazy but I can't find a central source for how to handle this anywhere. I figured, once we have an id_token perhaps we can take advantage of Amplify Auth's federatedSignIn but now instead of just passing in a provider, they do have an option to send in a provider name, an id token, and expiree time and a user object, as noted here
As you can see there's different ways you can use this function, so I figure now that I have the id_token back from the response, I can use this method to actually tell Amplify that yes I am indeed logged in. As such:
await Auth.federatedSignIn(
provider_name,
{
token: id_token,
expires_at: expires_in,
},
user
)
When this fires I get the following error:
issue with access token NotAuthorizedException: Invalid login token. Issuer doesn't match providerName
Now I have verified 100% that the providerName is correct. This is the SAME provider name we pass in the original federatedSignIn call. the id_token is also the jwt id_token we get back from the Cognito and the SSO provider. the expiree is also 3600 so im assuming thats valid, and if it wasnt, the error would be different. I am just lost as to what I need to do at this point.
How can I have amplify recognize a federated sign in user? Since all we get back is a access_token and im beginning to think im not using the federatedSignIn method properly.

Auth0: Specific questions about token storage and flow for mobile app

I’m building a react native app that will interact with APIs that I also write/manage. I have found Auth0 documentation for implementing this flow, but I’m not sure on where/when to save the tokens. I want to be sure I nail this step, because I feel like it has the potential to reduce the security of the flow by a great deal if I don’t do it correctly.
Here is the flow as I understand it (no error handling, only happy-path for sake of brevity):
A user enters the app for the first time, or is not already logged in
They log in using the Auth0 web-login-thingy
I receive a token
I can use the token to authenticate with my API
Questions:
Do I store that token? I don’t want my users to have to log in every time they use the app. If I do store the token, where do I store it?
If I’m not storing it, what do I do? Do I ping an authentication/authorization endpoint with Auth0 every time they open the app and get a new token?
Say I am storing the tokens, if I'm using the ID token for user data, should I be hitting the API again regularly to keep it up to date? Only when the user opens the app again? Not until they trigger a change in the app?
Instead of using the ID token for user data, should I just use that to get the user's ID and ping my database for user data?
I have the basics of this flow, and I'm able to sandbox it, but I want to start applying production-ready app logic to this flow and that's where I'm stuck. I’m a little lost here, so any help is good help.
Thanks!!
Here's a brief answer to your questions when using Auth0:
Yes! you store it, the most secure way to store the token is in your device's local storage, that way it is not kept either in application's state or in a global variable.
2&3. See above, but to add more information, you can configure your tokens to have an expiry length. in theory you would convert this 'expiry time from inception' to a date object, and can do one of two things; you can request a new token using the Refresh Token (that comes with the original) once the expiry has been reached, or force the user to re-log in and re issue a new token at this time (i prefer the latter, prevents people from just renewing their tokens forever as long as they remain logged in)
Use the auth token to request user information after login, this can be stored in app state/global variables/wherever. You then want to use the auth token in the Authorization Header for each API call, along with whatever data you are sending. this ensures that even once someone is INSIDE the application, they need to have a valid token to actually do anything involving data (imagine someone back-dooring into your app and skipping the authorization, or using something like postman to just hammer your API with garbage). it would work something like this: GET userData { Header: auth token } -> GET userProfile (by sending your user ID returned from GET userData) PLUS {Header: auth token }
I can give more in depth examples if you wish, and i apologize if i misunderstood any of the question and gave redundant/incorrect answers
Edit: Resources about using secure storage for keys
Document for when to use in-memory storage Vs persistent storage. The TL;DR is use in-memory if the key is expected to expire before a standard session duration, and persistent for storing a key between sessions
https://hackernoon.com/mobile-api-security-techniques-682a5da4fe10
link to Keychain Services doc
https://developer.apple.com/documentation/security/keychain_services#//apple_ref/doc/uid/TP30000897-CH203-TP1
link to SharedPreferences doc
https://developer.android.com/reference/android/content/SharedPreferences.html
AsyncStorage is a simple, unencrypted, asynchronous, persistent,
key-value storage system that is global to the app. [1]
You could store it in your AsyncStorage, but thats not necessarily a secure location itself (e.g. not encrypted, accessible on rooted devices...). Typically clients will issue access tokens that last anywhere from several hours to a couple days and these will provide their owner access to your API-resources. If there is sensitive data behind your login screen, you're probably better off simply re-doing the auth-flow and invalidate older access tokens on login.

Is it possible to use MSAL.js to get refresh token?

I want to integrate with Miscrosoft Outlook. I am able to login with MSAL.js and get an access token, but I am not able to get a refresh token. Is there a way to do it?
I'll assume that since you're using the MSAL.js (https://github.com/AzureAD/microsoft-authentication-library-for-js) that you're using implicit flow for authentication and authorization.
Implicit flow doesn't support refresh tokens, but you can request a new token silently. This is done similarly to how you request the token (id or access) in the first place. Unfortunately, I haven't found that MSAL.js does this transparently and I've needed to detect expired tokens and request the new tokens in my code. You can read more about refreshing tokens here.
Alternatively, if what you're implementing allows you to use one of the other MSAL libraries (for example, the .Net one) then you can use one of the other OAuth flows that explicitly support refresh tokens.
I couldn't find any answer in the MSAL.js documentation, however this source code comment suggests you can renew a token manually by passing only the clientId as your scope to acquireTokenSilent.
To renew idToken, please pass clientId as the only scope in the Authentication Parameters
I use msal v1.4.0
I remove 2 keys in storage (see picture) then call acquireTokenSilent again to get new access token.
Code to remove those 2 keys:
const keys = Object.keys(sessionStorage).filter(x => x.indexOf('authority') > 0)
keys.forEach(x => sessionStorage.removeItem(x))

Authentication on Instagram to get the access_token using the API

I'm using the Instagram API and want to get the access_token in order to throw api requests over my own account. When I try to follow the first step and get the authorization code programmatically using RestTemplate I can't get it work.
String AUTHORIZE_URL = "https://api.instagram.com/oauth/authorize/?client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&response_type=code";
String url = String.format(AUTHORIZE_URL, clientId, redirectUri);
String o = restTemplate.getForObject(url, String.class);
The response is the html code of the login page because Instagram requires the user to be logged in to check if the app is authorized (of course it is, since the app an the user belongs to my own account).
How can I authenticate before throwing that request so they return the code to my redirectUri and not complain about login?
Note: I tried simulating the request to their login form but it returned a 403 Forbidden.
NOTE: I already got a valid access_token, manually generated, and it works perfectly but I want to implement also a process to re-generate a new access_token automatically since they may invalidate it at any time in the future.
Even though our access tokens do not specify an expiration time, your app should handle the case that either the user revokes access, or Instagram expires the token after some period of time. If the token is no longer valid, API responses will contain an “error_type=OAuthAccessTokenError”. In this case you will need to re-authenticate the user to obtain a new valid token.
In other words: do not assume your access_token is valid forever.
Instagram is upgrading their APIs and the flows. Earlier we needed access token to bypass forced login screen. Since yesterday, they have removed that.
Now if you call this code, it will check if you are already logged in or not. If so, it will call the AUTHORIZE_URL of yours and will send a response code. The format will be either:
On success validation - http://your-redirect-uri?code=CODE
On error - http://your-redirect-uri?error=access_denied&error_reason=user_denied&error_description=The+user+denied+your+request
Now what I'm doing is I'm directly calling the above URL of yours every time. Now if the user is logged in, a response code will be sent to you, else user will be asked to login and validate your app and then the code will be sent. Technically, you are eliminating the possibility of the error case! So no need of overhead of storing access token in your database or verifying its validity.
Just try and check now what happens.
PS: If you want to check API behavior, simply type the URL on the browser and check what it returns! It helped me a lot while coding and debugging! :)