My requirement:
Using google login as the only login method for my website, creating users by google user id, creating authentication sessions after a valid google login.
I saw there was 2 ways to do this:
The standard google docs
(step 1) get id token at frontend https://developers.google.com/identity/sign-in/web/sign-in
(step 2) verify token id at backend https://developers.google.com/identity/sign-in/web/backend-auth
Using spring security OAuth functions
https://dzone.com/articles/getting-started-with-google-sign-in-in-spring-boot
So the problem is,
I just finished implementing measure 1 and found that after the login popup closes the state at frontend is changed. No typical OAuth2 elements like redirect_uri, code and access_token invovled in the process. So is this OAuth at all or is google just packed everything for me so I'm not seeing them?
Is measure 2 better? Because you don't have to deal with, let's say, the leak of id_token and client_id ?
The personas involved are different:
Front end: web OAuth2 flow with user involved. You request an authorization code with a redirect_uri for redirecting the user after the authentication. And then you validate this authorization code against the IDP server (you need a client ID and a client secret).
Back end: implicit OAuth2 flow with secret key file for the authentication, for app authentication. This flow is only to deploy on backend server, you absolutely don't have to share your secret key file in your website front end
EDIT
With your update, I'm not sure to understand. The 3 are equivalent
Pure OAuth flow
Google packaging (the function onSuccess() is called when the authentication is successful in the popup, as you can see in this example
Spring boot packaging.
At the end, the same information are provided and required, the "leak" are the same in all cases. It's simply a packaging preference and habit.
EDIT 2
For getting the access_token or the refresh token, you can simply do this as described here
accessToken = googleUser.reloadAuthResponse().access_token
Then, you can pass it to your backend if you want to perform operations on behalf of the user.
Related
We have a web app in which we allow users to log into the app using any Open ID provider(e.g. Okta, Google, Facebook etc.). We want to implement the correct Open ID Connect prescribed methodology/workflow to keep the user logged into the site.
The existing implementation, looks at the expiry of the Access Token then if it's close to expiry uses a Refresh Token to get a new Access Token to keep the user logged in. I feel like this is wrong. When a user logs in to the web app, the Identity Token is used to Authenticate the identity of the user using the Authorization Code workflow. The Access Token and Refresh Token are stored on the server side. Periodically, the Refresh Token is used to get new Access Tokens to keep the user logged into the site. I believe this is a security risk because -
Imagine if a user is logged onto his OP account in a browser. He opens up Sky and is directly logged into MP because he’s already logged into MP. He then in a separate tab, logs out of his OP account. He will continue to be logged into MP for days on the basis of this Refresh Token/Access Token mechanism! Isn’t this a security risk?
If feel like the correct way to go about this is to use Session Management using iframes as prescribed here on OIDC -
https://openid.net/specs/openid-connect-session-1_0.html
For more context, when a user logs into our WebApp we pull data from the OP's UserInfo endpoint to create a profile within our WebApp and set permissions/roles within our app based on data sent over from the OP's UserInfo endpoint. We continue doing this periodically. For this purpose, I feel like using the Access Token(and using the Refresh Token to get new Access Token) to access the UserInfo API is correct because it conforms to the OAuth 2.0 concept of protecting/authorizing API/Resource endpoints using Access Tokens.
I want to know if this is indeed the correct way to manage how a user should be logged in when supporting Open ID Connect.
I think the first question is whether you want to bind the lifetime of an OpenID Connect provider Single Sign On session with the session of your application. You just want to authenticate a user using their OpenID Connect service. If I logout of Google, I expect to be logged out of GMail, but not a third-party application that used Google for authentication. Would you like to implement Single Sign Out as well?
But if I wanted to be logged out when you logout of the OpenID Connect provider, I would implement the OpenID Connect Session management. There is one thing good to be aware of when using iframes and cookies - browsers have an option to "Block third-party cookies" (that's how Chrome calls it), it's turned off by default, but as far as I know, it disables the SSO functionality when turned on.
I'm not sure why you request the userinfo endpoint periodically. If you just want to check whether the access token is still valid, you could also use the token introspection endpoint.
For security concerns, I would suggest you to read the OAuth 2.0 for Browser-Based Apps RFC. It recommends using the auth code flow with PKCE instead of the implicit flow. With the implicit flow, access tokens transported in redirect URLs stay in network and browser caches and can be used right away by an attacker. The auth code with PKCE needs a code_verifier (one-time secret) in order to be exchanged for tokens. So I would first check how the providers work with a configuration you choose and if it's even supported.
I don't want to roll my own security anymore and am looking at using OpenID Connect with my c# API and AngularJS app. I can get all that to work just fine. However, my brain cannot seem to understand how to secure my API correctly for both use cases:
Use Case 1: AngularJS SPA
My AngularJS app connects to my API and sends a bearer token identifying the user and includes user claims. This one is easy and there is tons of documentation on it.
Use Case 2: API to API
Some customers want to access my API directly instead of going through my AngularJS app. In this case, I thought I could use a Client ID/Secret for toen-based authentication which is great except then I know nothing about the user that's using the client id/secret. There could be 10 users using the same custom API that is calling my API. How do I get user info via the API call? I've seen others use API keys that they then lookup the user and create a JWT but I thought there might be an easier way. Any ideas?
The whole point of API to API authentication is that there is no user context. Or well, the user in that case is the machine trying to access your API. You would then need to design your authorization logic around that and implement scope based permissions. Alternatively, your options are to use api keys as you mentioned or if you want OAuth protocol with user context in the api to api scenario - then ResourceOwnerCredentials flow is an option.
API to API communcation
You can use Client Credentials Grant defined through OAuth 2.0. This won't require you to have end user credentials. Now this won't be OpenID Connect. OpenID Connect require the involvement of an end user and bound to authentication. OAuth 2.0 on the other hand is about authorization, checking whether the entity can access the resource.
With Client Credential Grant, your identity server will issue tokens for a specific client. So one of your API becomes the client (resource consumer). From request handling API endpoint, you can accept valid tokens and respond back with resource.
If you require fine grained access control from request handling API, you will require to use token introspection to identify to whom this token was issued. In this case, it will be identification of specific client identity and execute a logic on top of it. You can check the token introspection response to identify such details.
Alternatively, access tokens can be come in form of a JWT. If this is the case, they can be considered as self contained tokens so validation is straightforward.
My project has the requirement to access the yammer data using the given REST API using server side script(mainly PHP) and not involve a client side login using yammer's OAuth dialog.
I have gone through this document:
https://developer.yammer.com/docs/oauth-2
but this says, we requires user interaction.
What I wanted was can I generate a client_id and client_Secret to further generate access token to make API call out, but in all these processes I only use the authenticated users username and password in my server-side script.
Can anyone suggest a solution or is a client-side interaction required by design?
Thanks in advance!!
You have to have a user authorize the application at least once. This is just the nature of the OAuth implementation and you can't work around it. Having users go through the OAuth flow is considered a best practice.
If you have an OAuth token for a verified admin of Yammer, you can use impersonation to get tokens for end users without them interacting with the OAuth flow.
The below from Microsoft blogs might help you & added source at the end of answer.
Obtain a Verified Admin token for your application in one of the following 2 ways
a. Create the app with a Verified Admin account and then in the app’s Basic Info page, click “Generate a developer token for this application.” Note that you’ll need to use this app’s info in the JS SDK and any subsequent calls.
b. Use the process outlined at https://developer.yammer.com/docs/test-token with a Verified Admin account to get an OAuth token for that VA account. Note that you must use the app info used to generate this token in all future steps.
Obtain the current user’s email address in the server-side script.
Using the VA token obtained in step 1 to authenticate, pass the user’s email address to our Get User by Email Address endpoint documented at https://developer.yammer.com/docs/usersby_emailjsonemailuserdomaincom, and then process the response
a. If the call to the API endpoint returns a 200 OK response, first check the “state” field to make sure the user is “active” and if so, store the “id” field that’s returned and go to step 4
b. If the call returns a 404 or a state other than “active,” direct the user to finish creating and activating their account however you like.
Once you have the user’s ID, you can pass it to our Impersonation endpoint to obtain a pre-authorized OAuth token for that user. This endpoint is documented at https://developer.yammer.com/docs/impersonation and must use the VA token obtained in step 1 to authorize the call, and the consumer_key of your JS SDK app.
You now have an OAuth token for the current user. When generating the code being passed to the browser, have the client side JS SDK code first call yam.platform.getLoginStatus and if there’s no active session and you have a token from step 4, pass that token to yam.platform.setAuthToken($tokenFromStep4, optional_callback_function_if_desired(response)). If you don’t have a valid token, direct the user to finish setting up their Yammer account.
Continue making JS SDK calls as you normally would, without needing the user to authenticate.
Source: https://blogs.technet.microsoft.com/askyammer/2016/11/04/preauthorizing-the-yammer-js-sdk/
I am trying to implement a OAuth2 Provider, that authenticates users with a custom login.
For understanding I looked at the Spring Boot OAuth2 Tutorial.
I don't quite get, how I can implement my own Authentication meachnism to work with the OAuth2 SSO from my Server.
I want to add custom authentication mechanisms (like "user has to answer a question for authentication" or "user has to enter id and click button for authentication") instead of the Facebook and Github examples.
I read about implementing my own AuthenticationProvider, but I am stuck how to combine all the puzzle parts.
Let's go one step at a time. OAuth is only authz provider so not talk about authentication. Now for your usecase specifically, if you want user to be authenticated then OAuth authz code based flow makes sense (You can even go for implicit flow, check rfc 6749). Now how will this work for you. I am picking up the implicit flow for simplicity, Authz flow is just extension of it where end client gets a temporary code which it exchanges with Identity Server later to get the access token. Here are the steps:
Client App hits the /authorization uri with data as per rfc 6749
After validating the submitted data, server forwards user to Login page (or other page for authentication). After authentication, cookie is set in the browser or data is stored in server to mark a user as authenticated.
After authentication server redirects user to user consent page (You can even skip this if needed depending on need, But OAuth 2 spec contains this) where user specifies which all permissions (scopes) are allowed, here user can allow either allow or deny.
if user allows then these permissions are submitted to server and then server stores the data and redirects the user to client URI with access token in # fragement of client redirect URI (callback URI submitted during actual request)
I’m trying to get my head around how I would introduce token-based (key-based?) authentication to a web API (currently looking at Sinatra, but maybe Rails too) that would be used by a mobile client and how OAuth would fit into the picture.
So, let’s say I want to create a web service that uses Facebook for authentication and grabbing basic user data. Here, my API would be a client to Facebook’s OAuth Server, requesting an access token upon a user’s successful login to Facebook. This would then grant me access to the user’s data which I would use to create an entry in my database, storing this user-specific token with any other application information I would like linked to them.
I think I got that part right so far, but here’s where I’m a bit confused.
I think that my API would also need some form of API key to grant access to a mobile user, since I wouldn’t want to transmit and store the Facebook key on their device. Would I have to have a separate store of keys which I provide to the client to access my service? Are there any ‘best practice’ ways of doing this?
Would I have to have a separate store of keys which I provide to the client to access my service?
yes.
Are there any ‘best practice’ ways of doing this?
The simplest way would be to generate a separate authentication token on every User creation and expose that to the mobile client. Then send it with every subsequent request header.
Devise provides a simple example how to achieve that. You don't need devise for that, just provide some token generation mechanism.
#Devise.friendly_token
def self.friendly_token
SecureRandom.urlsafe_base64(15).tr('lIO0', 'sxyz')
end
This mechanism can be extended to provide more security in following ways
Being an oauth2 provider itself.
On successfull login with facebook, you would generate an :authorization_code which the client can exchange for your own Oauth2 Bearer or MAC token within a next step. Then you can send your own Oauth2 token with every request for user authentication.
See rack-oauth2
Implement HMAC token encryption.
Generate and expose a secret_key to every client after singning in. Use this secret to sign messages along with a unique client id. The server can then lookup the secret_key for the specific client_id and verify the message.
See api-auth