How to handle oauth2 using NextJS? - cookies

Here are my steps of authorization:
When the user clicks sign in with a third party oauth provider, the user is redirected to the third party's website.
The user signs in using third party and third party returns the data to the redirect address I provided (in my example: http://localhost:3000/api/login). Third party sends GET request with a code attached to its uri query.
I use the code provided along with my other credentials to send to the third party endpoint to receive something like this:
{
access_token: '1IqfasasdfsadfasdtS795sadfasdfasdfasd',
refresh_token: '2frsadfasfdat5bGhrs6YTtCqY5h0asdfasdfasdfasdf',
token_type: 'Bearer',
expires_in: 3600,
refresh_expires_in: 2592000,
scope: 'user_profile'
}
What is the best way to handle the refresh token and access token? I ideally want to store the access token to browser's session storage and refresh token to http only cookie, but I can't figure out a way to pass the access_token from backend to browser, where for cookie I can just do a res.setHeader, is there something like res.setSessionStorage? Or what are my other alternatives?

Have you checked out NextAuthJS? Open source. Built in oauth/oidc providers and supports custom ones too. It was fairly easy to use, once you got the setup right.
https://next-auth.js.org/

Related

How to integrate Facebook Login in django-graphql-jwt?

We have a django project that uses the Graphene-Django library to implement a GraphQL API in our project. This backend is accessed by our mobile apps. For the authentication of the apps, we use the django-graphql-jwt library, which is a JSON Web Token library in Django with GraphQL approach.
Now we want to implement the Facebook Login in our system and with it the authentication happens in Facebook. After authentication, what will be sent to our backend from the mobile app is only the email of the user. How can I register and authenticate the user in django-graphql-jwt without the password? Or is there a better workflow for this?
After authentication, what will be sent to our backend from the mobile app is only the email of the user.
Hey Al Ryan, this seems like a faulty implementation of OAuth, what you get back from facebook is a token you send that token to your server, and it will send it back to facebook to verify it's not faked, then only user can be logged in.
Otherwise anyone can call the server with a email and act as that user.
This is a library with social auth and JWT support, see if this helps.
I'm also sharing solution from my project
Create a facebookAuth named graphql mutation
Above mutation will take two params access_token and access_verifier
Send a GET request to this url f"https://graph.facebook.com/me?fields=name,email&access_token={access_token}"
If json response has a key errors, stop user from logging in.
Otherwise above response will contain email, use it to create/get a User object.
Now you simply need to return the JWT token from your mutate function.
To generate access and refresh tokens call this function jwt_encode, imported as from dj_rest_auth.utils import jwt_encode
above will return tuple access_token, refresh_token
Note I have used dj_rest_auth instead of django-graphql-jwt, but it's pretty equivalent you just need a function to sign the JWT, rest all is custom logic so better write yourself.
PS: OAuth is a sensitive entry-point for attackers so implement is securely, you can contact at atul7555[at]gmail.com for any assistance.

How does Postman handle localhost OAuth 2 redirects?

When using Postman to fetch an access token via Authorization Code, one of the fields I need to enter is for the Callback URL, aka the redirect URI query param when it's making the request to the authorization endpoint. I understand this URL needs to be registered/whitelisted within the OAuth provider, but my question is how does postman actually handle/intercept that request/redirect back when it's localhost-based? For example, if I already had a local server running on http://locahost:8090, and I told postman to use http://localhost:8090 for that callback, how does Postman end up seeing that request/redirect back (to exchange the auth code for an access token) instead of my local web server handling that request?
TL;DR: Postman basically ignores the callback URL when processing the response.
The Long Story
It does need it, but only for the request. As you say, it needs to be correct - exactly matching the IdP client application config - but that's it.
Postman is just helping you acquire the token, it doesn't need to provide it to the consuming application, which is the whole point of the redirect URL - a static path known by the client app and the OAuth client application that makes sure an evil website / intermediary doesn't steal tokens by abusing the redirection flows.
Since it's not meant to work on a browser on the internet, Postman can ignore the redirect. Once the IdP responds with the token then, as far as Postman is concerned, it's good to go. It can save the token in the local token store and use it to make API requests.
Implicit Flow
This is set up to get a token from an Okta endpoint:
When I click "Request token", Postman makes a request like this:
GET https://exampleendpoint.okta.com/oauth2/default/v1/authorize?nonce=heythere&response_type=token&state=state&client_id={the_client_id}&scope=profile%20openid&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fimplicit%2Fcallback
Postman pops a browser to make this request to the /authorize endpoint, at which the IdP then either creates the token (if the browser already has a cookie), or performs various redirects to authenticate the user and then create the token.
At the end of this flow, Postman will receive the 302 from the IdP that contains the token (on the location header). The target of that redirect is the redirect URL configured in the IdP:
302
Location: http://localhost:8080/implicit/callback#access_token=eyJraWQiOiJxOGRmTGczTERCX3BEVmk4YVBrd3JBc3AtMFU1cjB6cXRUMFJveFZRUVVjIiwiYWxnIjoiUlMyNTYifQ.{the_rest_of_the_token}&token_type=Bearer&expires_in=3600&scope=profile+openid&state=state
At this point Postman grabs the token from the #access_token parameter and it's good to go.
Auth Code Flow
Auth Code flow comes in 2 flavours:
Auth Code (Classic)
Auth Code + PKCE
Auth Code flow has been seen as "better" than the implicit flow because it requires a 2nd step in the process to get an access token. You hit authorize which gives the client a code and the code is then exchanged for the tokens. This code for token gives more chances for the server side components to do more stuff - extra checks, enrich tokens and various other things.
Q: Why are there 2 Auth Code flows?
A: The problem with this was that it required a server side component, which many SPA's and/or mobile apps didn't want to host. The endpoint that receives the code and gets the token(s) had to maintain credentials - a client id and client secret - which are required by the IdP when creating the token. PKCE is an extension that removes the requirement for a trusted server. It's adds computed hash to the /authorize call, which the IdP remembers, and then on the subsequent call to /token the client provides the source value of the hash. The server does the same computation, checks it's the same as that on the original request and is then satisfied that it's not handing out tokens to a bad guy.
Auth Code with PKCE
In terms of redirects, this is exactly the same as implicit. But for requests, it needs to make the second request to exchange the code for the tokens. The main differences here are
the access token URL, which is where to send the code and get tokens in response.
the code challenge and verifier, which are PKCE requirements for generating and computing the hash
The requests are now as follows:
The GET to /authorize
GET https://exampleendpoint.okta.com/oauth2/default/v1/authorize?nonce=heythere&response_type=code&state=state&client_id={client_id}&scope=profile%20openid&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fimplicit%2Fcallback&code_challenge=E7YtiHqJRuALiNL_Oc5MAtk5cesNh_mFkyaOge86KXg&code_challenge_method=S256
Postman will pop the browser (and the IdP will redirect it through login if required)
The eventual code response is also 302, however the location header contains the code rather than tokens:
location: http://localhost:8080/implicit/callback?code=J3RlQqW122Bnnfm6W7uK&state=state
So now the client needs to call the endpoint defined in the "Access Token URL" field to get tokens:
POST https://exampleendpoint.okta.com/oauth2/default/v1/token
Body:
grant_type: "authorization_code"
code: "J3RlQqW122Bnnfm6W7uK"
redirect_uri: "http://localhost:8080/implicit/callback"
code_verifier: "Fqu4tQwH6bBh_oLKE2zr0ijArUT1pfm1YwmKpg_MYqc"
client_id: "{client_id}"
client_secret: ""
And the response is a good old 200 that doesn't redirect - the authorize call sends the client back to the final redirect landing page, and the POST is just a normal request with the tokens on the the response
{"token_type":"Bearer","expires_in":3600,"access_token":"eyJraWQiOiJxOGRmTGczTERCX3BEVmk4YVBrd3JBc3AtMFU1cjB6cXRUMFJveFZRUVVjIiwiYWxnIjoiUlMyNTYifQ.*******","scope":"profile openid","id_token":"eyJraWQiOiJxOGRmTGczTERCX3BEVmk4YVBrd3JBc3AtMFU1cjB6cXRUMFJveFZRUVVjIiwiYWxnIjoiUlMyNTYifQ.********"}

Cognito user pool for single admin

I'm trying to create a personal blog using s3 and lambda. I already have the API setup but I'm trying to figure out how to make the blog post requests more secure by requiring an authorization token in order to access the API Gateway.
I believe this can be done with cognito user pools but is usually used with many users not a single admin user. However, if there's another way I should go about this then I'm all ears.
You can implement this by:
Creating a User Pool in Cognito
If you are using the Hosted UI login pages, I recommend having the pages send a code response rather than a token response because you can call the token endpoint to get all the appropriate tokens.
Call your token endpoint with the code you receive in Step 2 (it'll be in the URL when you are redirected back to your site) to retrieve the ID, Access, and Refresh Tokens.
Once you have your cognitoUser tokens, you can wrap your blog publish function with a token check function to ensure that your token is up-to-date and send the updated token to your publish blog callback.
Send the user token in your headers: { Authorization: token } API Call.
In API Gateway, choose the Method Request in your Blog Post API and select your Cognito User Pool name under authorizers.
As long as the token you send is valid, the Method Request is all you need to update in order to secure the ability to post.

How can I get a response when calling Slack's oauth/authorize?

When I try to make the following call using postman I get no response: https://slack.com/oauth/authorize?client_id={{client id}}&scope=chat:write:bot
However, when I try it without the scope I do get a response, saying I need to add a scope.
I've put this call together according to the first step of https://api.slack.com/docs/oauth
I've tried using both GET and POST verbs and my header is empty.
What can I do to get a authorization token for Slack?
This is part of the OAuth flow/spec.
What you need to do to is follow/perform the OAuth flow:
Register your application with slack
Provide a redirect_uri - this is the callback URI - this callback/handler will be called with the authenticationCode by the slack OAuth server.
Only if the user authorizes your app, Slack will redirect back to your specified redirect_uri with a temporary code in a code GET parameter, as well as a state parameter if you provided one in the previous step.
It's true that the redirect url is optional, but if left out, Slack will redirect users to the callback URL configured in your app's settings.
the authenticationCode then needs to be changed in code to the accessToken.
So if all is well and user gave its consent, you need to exchange the authorization code for an access token using the OAuth.access API method (method documentation), int the following URL and retrieve your accessToken.
https://slack.com/api/oauth.access
if you decide to use a bot user and your Slack app includes a bot user, you will get an additional node containing an access token to be specifically used for your bot user.

Using coldfusion session id for SSO authentication

I am integrating a 3rd party application. It will be embedded into my site via an iframe. When instantiating the iframe, a username and unique id(sessionid) is sent to the third party app in this format:
http://www.thirdpartyapp.com?username=9999999&uuid=appname_11111_d3d379ab97c23930-154C9639-1CC4-6169-286F5EB34A37B3C3
Once the user on the site tries to use any of the functions inside the Iframe, the 3rd party app sends back the sessionid to the server, to validate if the session is logged in.
If a user is logged in, the application sets a session variable such as Session.Auth.Authenticated to true.
I am able to achieve this by using CFID and CFTOKEN like so:
http://www.mysite.com/checkauth/index.cfm?CFID=2223344&CFTOKEN=40487e5933d11e75-F94396AF-1CC4-6169-28200888416FFC
The third party app sends requests in the format:
http://www.mysite.com/checkauth/index.cfm?uuid=appname_11111_d3d379ab97c23930-154C9639-1CC4-6169-286F5EB34A37B3C3
Basically the same format as my site makes the request. Is there any way to check authenticated sessions using the session.sessionid?
"Is there any way to check authenticated sessions using the
Session.sessionid?"
Seems like it is possible. The ColdFusion sessionid is consists of three things:
appName_CFIDE_CFTOKEN
In your case the format of the url parameter of the request send by third party application is same as session.sessionId:
appname_11111_d3d379ab97c23930-154C9639-1CC4-6169-286F5EB34A37B3C3
Now if you enable "Use UUID for cftoken" in CF Admin under "settings" section you will get session id like the following:
PLANTOMATIC_11201_1f8a073a0ba85bf5-2F7356F3-BE59-A0B4-F3E493BD794062C6
So what you need to do is apply the setting "Use UUID for cftoken" in CF Admin. Then you can send request to the third party like following:
http://www.thirdpartyapp.com?username=9999999&uuid=#session.sessionid#
Which will respond back with parameter "uuid". After that you can check for equality and take the necessary steps.