Firebase iOS Auth with Twitter + Make requests on backend (403 status code) - firebase

i've succesfully integrated Twitter Auth via my iOS app and firebase, as explained here: https://firebase.google.com/docs/auth/ios/twitter-login
I'm able to get an oauth access token + secret from the user that authorizes the connection via app.
My intention was to use the oauth access token to make requests via the node-twitter-api-v2 library, for example - fetching the user's bookmarks.
I tried using the access token in place of the "bearer token" when initializing the TwitterApi client, but am still getting the error:
Authenticating with OAuth 2.0 Application-Only is forbidden for this endpoint. Supported authentication types are [OAuth 1.0a User Context, OAuth 2.0 User Context].
From my understanding, such requests must be made via a "logged in" client and the v2 api - question is, is there a way to use the already authed user's (via app) token to make the request / log in? This is done via background + backend, so the idea is that there is no UI / callback to make the user go through to create the logged in session.
Any ideas on how to approach this or if it's even possible?
Example code:
//call the new v2 api
const bookmarkedTweets = await this.twitterClient.v2.bookmarks({
max_results: max_fetch_limit,
expansions: ['attachments.media_keys'],
'media.fields': ['preview_image_url', 'url', 'variants'],
'tweet.fields': ['created_at', 'entities', 'attachments', 'author_id', 'conversation_id', 'id', 'text'],
});
Error response:
data: {
> title: 'Unsupported Authentication',
> detail: 'Authenticating with OAuth 2.0 Application-Only is forbidden for this endpoint. Supported authentication types are [OAuth 1.0a User Context, OAuth 2.0 User Context].',
> type: 'https://api.twitter.com/2/problems/unsupported-authentication',
> status: 403
> }
From what i read in twitter docs, once we get the token form user, all we need to do is just call the endpoints with the token as the Bearer, but this does not seem to work (maybe i read instructions wrong).
**
* Create a new TwitterApi object with OAuth 2.0 Bearer authentication.
*/
constructor(bearerToken: string, settings?: Partial<IClientSettings>);
Any help would be greatly appreciated. Thank you

Related

How is this access token stored on the client, in FastAPI's tutorial "Simple OAuth2 with Password and Bearer"

I'm pretty new to FastAPI and OAuth2 in general. I just worked through the tutorial "Simple OAuth2 with Password and Bearer" and it mostly made sense, but there was one step that felt like magic to me..
How does the access token get stored onto the client and subsequently get passed into the client's requests?
My understanding of the flow is that it's basically
User authenticates with their username and password (these get POST'ed to the /token endpoint).
User's credentials are validated, and the /token endpoint returns the access token (johndoe) inside some JSON. (This is how the user receives his access token)
???
User make a subsequent request to a private endpoint, like GET /users/me. The user's request includes the header Authorization: Bearer johndoe. (I don't think the docs mention this, but it's what I've gathered from inspecting the request in Chrome Developer Tools)
The authorization token is then used to lookup the user who made the request in (4)
Step (3) is the part that I don't understand. How does the access token seemingly get stored on the client, and then passed as a header into the next request?
Demo
When you run the code in the tutorial, you get the following swagger docs. (Note the Authorize button.)
I click Authorize and enter my credentials. (username: johndoe, password: secret)
And now I can access the /users/me endpoint.
Notice how the header Authorization: Bearer johndoe was automagically included in my request.
Last notes:
I've checked my cookies, session storage, and local storage and all are empty
The authorization header disappears if I refresh the page or open a new tab
I suspect Swagger is doing something under the hood here, but I can't put my finger on it.
If you need persistence for the token you'd usually use localStorage or similar, but in SwaggerUIs specific case, the authentication information is kept internally in the library.
If you have enabled persistence SwaggerUI will persistent the access token to localStorage:
export const persistAuthorizationIfNeeded = () => ( { authSelectors, getConfigs } ) => {
const configs = getConfigs()
if (configs.persistAuthorization)
{
const authorized = authSelectors.authorized()
localStorage.setItem("authorized", JSON.stringify(authorized.toJS()))
}
}

Firebase admin - get Google OAuth token

I have a web application where users can sign in with Google.
To the sign-in process, I add a scope to be able to access Google Calendar.
Now that the user is signed in, I would like to - in server-side - get their current Google access token in order to make a request and get a list of their events.
Is there a way to get the current OAuth token (no need for refresh token) in order for me to make this completely on the server-side?
I'd say that you can check this article and put special attention to the recommendation for websites.
I understand you have configured already the consent screen, which is the first step of the basic steps on using OAuth 2.0. So I understand that you only have to perform the following steps:
Obtain an access token from the Google Authorization Server
Examine scopes of access granted by the user.
Send the access token to an API
I think you can also give a look to this other doc for more GCP insights over your goal to authorize the request using user tokens
Edited:
Regarding the Firebase Authentication, I understand this happens at the user's device, and you could use some code to retrieve the token and then send it to your back end servers as mentioned in here.
As a sample here there's the sample code for retrieving the token in Android:
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
String idToken = task.getResult().getToken();
// Send token to your backend via HTTPS
// ...
} else {
// Handle error -> task.getException();
}
}
});
A little about OAuth 2.0
Whenever a user signs up to your app/website via Google or 3rd Party, an Authorization Code, this Authorization Code is exchanged for an AccessToken & RefreshToken.
The AccessToken sent via Google are valid generally for 60 minutes.
Offline Access (Server Side)
Let's break it down to two parts:
If your need to update within 60 minutes of user's last activity
You can use firebase along with gapi to achieve that. You'll be provided with the AccessToken that can be sent back to server to add to calendar.
More info on implementation
If you need to update after 60 minutes of user's last activity
Firebase & gapi's most method handle the AuthorizationCode flow internally. They even further refresh the AccessToken after 60 minutes. This is beneficial for most developers as they won't have a headache of managing all the tokens.
This method but, hides RefreshToken & AuthorizationCode from the developer. That is even if your server has the access token, it won't be able to refresh it and it would be deemed useless.
To achieve complete offline access, in the initial request to get AuthorizationCode you will need to send a HTTP GET parameter access_type to offline
GAPI provides you with grantOfflineAccess() method which returns the AuthorizationCode that can be later used on your server to fetch access token & refresh token.
Note: If you are storing AuthorizationCode in your database, make sure it is secure. The limitation in Firebase are set due to security reason. It is more secure to not talk with AuthorizationCode generally.
More links
https://developers.google.com/identity/protocols/oauth2/web-server
https://developers.google.com/identity/sign-in/web/reference
https://developers.google.com/identity/sign-in/web/server-side-flow
https://developers.google.com/identity/sign-in/web/backend-auth
Retrieve Google Access Token after authenticated using Firebase Authentication

sign in with slack and validate request from firebase backend for the angular app

i have built a webapp using angular material and firebase functions + realtime DB as the backend. I am using slack "Sign in with Slack" API oauth flow. All works well and i am able to generate a accessToken in the backend which i can store against the user in the realtime DB. Once that is done i make a redirect call to my angular app on the dashboard page. Currently i am passing userid in the redirect url which i use to drive user to dashboard and show his data.
This functionally works fine but is a big security issue. As i can directly type the redirect url and boom. I am in the dashboard.
So, how do i solve this? What should i be doing in the url redirect that is secure and validates the response is the the result of a valid request?
I am not familiar with the Slack OAuth SDK but in general, this is true for all OAuth providers. Ideally, at the point where you redirect to your callback URL with the slack authorization code and you exchange the auth code for a Slack access token before returning that access token to the client, you call the Slack API to get the Slack user ID with the access token and then mint a Firebase custom token with that uid. You then return that custom token to the client and signInWithCustomToken. Make sure you are checking the state field (which you set when started the Slack sign in) along with Auth code to verify that the flow started and ended on the same device.

Authenticate with signInWithCredential()

I'm trying to connect to the second Firebase app and authenticate with signInWithCredential(), but I don't know how to get valid idToken for the second app:
connect(accessToken: string, config: FirebaseAppConfig) {
let one: firebase.app.App = this.angularFireTwo.database["fbApp"];
one.auth().currentUser.getToken()
.then(idToken => firebase.auth.GoogleAuthProvider.credential(idToken, accessToken))
.then(credential => {
let two = firebase.initializeApp(config, `[${config.apiKey}]`);
return two.auth().signInWithCredential(credential);
})
.catch(console.warn)
.then(console.info);
}
I'm getting and error from https://www.googleapis.com/identitytoolkit/v3/:
Invalid id_token in IdP response
If I use signInWithPopup() I can authenticate and connection is working:
two.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider())
Anyone knows what should I do to get valid idToken?
UPDATE:
I've been trying to figure out authentication process and, as far I understand it , it's something like this:
from config: FirebaseAppConfig firebase reads apiKey and authDomain
it contacts the servers and gets Web Client ID for enabled Google provider 123.apps.googleusercontent.com
with this Web Client ID and authDomain it contacts www.googleapis.com, which returns idToken
this idToken is then used to identify the app that's asking user for permission to access user's profile, etc.
when user agrees, callback returns user details + credential used for this authentication, which contains idToken of the web app and accessToken of the user
Now, if I use signInWithPopup() steps 2-3-4 are done in the background (popup window). I just need a way to generate idToken for the step 4, so I can use it to generate credential firebase.auth.GoogleAuthProvider.credential(idToken, accessToken) and sign-in using signInWithCredential().
I have access to everything I need to sign-in to the second app - it's; apiKey, authDomain, Web Client id 456.apps.googleusercontent.com, and user's unique accessToken.
But still can't figure out how to do it. I tried white-listing apps' one and two Web client IDs in their auth configurations, hoping that will allow them to accept each others idTokens, but that didn't work...
When you call:
firebase.auth.GoogleAuthProvider.credential(idToken, accessToken))
The first parameter should be a Google OAuth Id token. You are using the Firebase Id token and that is why you getting the error. Besides, if you are already logged in, why are you logging in again with signInWithCredential?
If you need to sign in with a Google credential you need either a Google OAuth Id token or a Google OAuth access token.
To duplicate Firebase OAuth sign-in state from one app to another, you get the credential from signInWithPopup result and use it to signInWithCredential in the second instance.
two.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider())
.then(function(result) {
return one.auth().signInWithCredential(result.credential);
});

{"error":"invalid_client","error_description":"The client credentials are invalid"} in fosoauth bundle

I tried to to use the FOSOAuthServerBundle for authenticating the users respective to their access token.
I did all the settings as per the link: http://blog.tankist.de/blog/2013/07/17/oauth2-explained-part-2-setting-up-oauth2-with-symfony2-using-fosoauthserverbundle/
As an output I receied the client id and the client secret key but I am confused about the grant_type..what values does it hold??
And while running this in browser: http://external.apostle.digibiz.com/web/app_dev.php/oauth/v2/token?client_id=1k1x8xpqbjnogs88cso0gwwk4848oocsscsgwcwowcck4840s8&client_secret=3ntf3p6h6c6c04g4o08ggkgcwc0co0sk804gwckow88g0ggck0&grant_type=client_credentials
the following is given as error:
{"error":"invalid_client","error_description":"The client credentials are invalid"}
How can I solve this error????
You can find list of supported grant types at oauth2 repo in class OAuth2. Here are they:
/**
* Grant types support by draft 20
*/
const GRANT_TYPE_AUTH_CODE = 'authorization_code';
const GRANT_TYPE_IMPLICIT = 'token';
const GRANT_TYPE_USER_CREDENTIALS = 'password';
const GRANT_TYPE_CLIENT_CREDENTIALS = 'client_credentials';
const GRANT_TYPE_REFRESH_TOKEN = 'refresh_token';
const GRANT_TYPE_EXTENSIONS = 'extensions';
Grant type specifies how client can be authenticated in application. Detailed explanation can be found in OAuth2 spec but it's spread around the document. Precise meaning of each grant type based on my knowledge of OAuth2 Server bundle:
authorization_code - client is identified and authenticated by code parameter obtained earlier from server
password - client is authenticated by user's credentials: user and password
client_credentials - client is authenticated by it's own credentials (the ones you've provided during client creation)
implicit - one step authentication. Not recommended unless you know what you're doing
refresh_token - client is authenticated by refresh token provided in original authentication. OAuth token issued earlier becomes invalid
extensions - ???
You can provide more than 1 grant_type per client. Also I recommend you to read great article OAuth2 Simplified

Resources