Merge pull request #25069 from backstage/freben/auth-doc
document the auth service triplet
This commit is contained in:
@@ -5,4 +5,136 @@ sidebar_label: Auth
|
||||
description: Documentation for the Auth service
|
||||
---
|
||||
|
||||
TODO
|
||||
This service deals with the generation and verification of tokens and their
|
||||
associated representations as credentials objects. You can use it for validating
|
||||
incoming tokens, and generating tokens for calling other services.
|
||||
|
||||
If you want to deal with credentials specifically in the HTTP request/response
|
||||
flow, see also [the `httpAuth` service](./http-auth.md). If you want to extract
|
||||
more details about authenticated users such as their ownership entity refs, use
|
||||
[the `userInfo` service](./user-info.md).
|
||||
|
||||
## Using the Service
|
||||
|
||||
In the following code examples, the `auth` and `httpAuth` variables are assumed
|
||||
to be dependency-injected instances of the `coreServices.auth` and
|
||||
`coreServices.httpAuth` service, respectively. For a backend plugin, it might
|
||||
look like this:
|
||||
|
||||
```ts
|
||||
export default createBackendPlugin({
|
||||
pluginId: 'my-plugin',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
auth: coreServices.auth,
|
||||
httpAuth: coreServices.httpAuth,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
},
|
||||
async init({ auth, httpAuth, httpRouter }) {
|
||||
// Your code goes here
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Creating Request Tokens
|
||||
|
||||
If you need to create a token that can be used for making a request to another
|
||||
backend plugin:
|
||||
|
||||
```ts
|
||||
const { token } = await auth.getPluginRequestToken({
|
||||
onBehalfOf: await auth.getOwnServiceCredentials(),
|
||||
targetPluginId: 'catalog',
|
||||
});
|
||||
```
|
||||
|
||||
:::note Note
|
||||
|
||||
Never store and reuse tokens. Always call `getPluginRequestToken` immediately
|
||||
before making a request. Otherwise you run the risk of running into permission
|
||||
problems when expired tokens are being used for requests.
|
||||
|
||||
:::
|
||||
|
||||
This example is suitable when you need to make the request "as your own plugin",
|
||||
i.e. when your code is the original initiator of the call. An example of this
|
||||
could be periodic batch processes that index content in another service.
|
||||
|
||||
In situations where you are making a call on-behalf-of someone else, for example
|
||||
when making upstream requests inside a request handler, please always instead
|
||||
use the extracted credentials from the request.
|
||||
|
||||
```ts
|
||||
router.get('/makes-calls', async (req, res) => {
|
||||
const { token } = await auth.getPluginRequestToken({
|
||||
onBehalfOf: await httpAuth.credentials(req),
|
||||
targetPluginId: 'catalog',
|
||||
});
|
||||
// make a call using the token
|
||||
```
|
||||
|
||||
This ensures that the original caller and their associated permissions are
|
||||
properly carried along with the request chain. See [the `httpAuth` service docs](./http-auth.md)
|
||||
for more details.
|
||||
|
||||
The [service to service auth docs](../../auth/service-to-service-auth.md)
|
||||
contain more details about how to properly use tokens in your HTTP request
|
||||
paths.
|
||||
|
||||
### Authorizing Tokens
|
||||
|
||||
Most plugins should not deal with incoming request tokens directly at all, but
|
||||
rather use [`httpAuth.credentials`](./http-auth.md) instead as part of their
|
||||
request handlers. But in the rare cases where you are holding an incoming token
|
||||
and want to validate it and turn it into a credentials object, you can do so:
|
||||
|
||||
```ts
|
||||
const credentials = await auth.authenticate(token);
|
||||
```
|
||||
|
||||
There is an optional second parameter that you can set to `{ allowLimitedAccess:
|
||||
true }` if you specifically built a plugin that deals with cookie based access,
|
||||
which is rare.
|
||||
|
||||
### Inspecting Credentials
|
||||
|
||||
The `auth` service also contains facilities for working with credentials
|
||||
objects. For example checking what type of principal (caller type - e.g. user or
|
||||
service) they represent. For example:
|
||||
|
||||
```ts
|
||||
if (auth.isPrincipal(credentials, 'user)) {
|
||||
// In here, the TypeScript type of the credentials object has been properly
|
||||
// narrowed to `BackstageCredentials<BackstageUserPrincipal>` so you can
|
||||
// access its specific properties such as `credentials.principal.userEntityRef`.
|
||||
}
|
||||
```
|
||||
|
||||
## Configuring the service
|
||||
|
||||
:::note Note
|
||||
|
||||
The `auth` service is not suitable for having its implementation replaced
|
||||
entirely in your private repo. If you desire additional service auth related
|
||||
features, don't hesitate to [file an issue](https://github.com/backstage/backstage/issues/new/choose)
|
||||
or [contribute](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) to the open source features.
|
||||
|
||||
:::
|
||||
|
||||
For configuring service-to-service access methods, see [the auth docs](../../auth/service-to-service-auth.md).
|
||||
|
||||
The default auth policy requires all requests to be authenticated with either
|
||||
user or service credentials. This can be disabled by setting the
|
||||
`backend.auth.dangerouslyDisableDefaultAuthPolicy` app-config flag to `true`.
|
||||
Disabling this check means that the backend will no longer block unauthenticated
|
||||
requests, but instead allow them to pass through to plugins. Do not do this in
|
||||
production unless absolutely necessary.
|
||||
|
||||
If permissions are enabled, unauthenticated requests will be treated exactly as
|
||||
such, leaving it to the permission policy to determine what permissions should
|
||||
be allowed for an unauthenticated identity. Note that this will also apply to
|
||||
service-to-service calls between plugins unless you configure credentials for
|
||||
service calls.
|
||||
|
||||
@@ -5,4 +5,102 @@ sidebar_label: Http Auth
|
||||
description: Documentation for the Http Auth service
|
||||
---
|
||||
|
||||
TODO
|
||||
The `httpAuth` service deals with submitting and receiving credentials on Express
|
||||
HTTP request/response objects. This service is frequently used in plugins that
|
||||
have REST interfaces.
|
||||
|
||||
If you want to deal with raw tokens and do low level credentials handling, see
|
||||
also [the `auth` service](./auth.md). If you want to extract more details about
|
||||
authenticated users such as their ownership entity refs, use [the `userInfo` service](./user-info.md).
|
||||
|
||||
## Using the Service
|
||||
|
||||
In the following code examples, the `auth` and `httpAuth` variables are assumed
|
||||
to be dependency-injected instances of the `coreServices.auth` and
|
||||
`coreServices.httpAuth` service, respectively. For a backend plugin, it might
|
||||
look like this:
|
||||
|
||||
```ts
|
||||
export default createBackendPlugin({
|
||||
pluginId: 'my-plugin',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
auth: coreServices.auth,
|
||||
httpAuth: coreServices.httpAuth,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
},
|
||||
async init({ auth, httpAuth, httpRouter }) {
|
||||
// Your code goes here
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Getting Request Credentials
|
||||
|
||||
If you need to extract the validated credentials out of an incoming request, you
|
||||
can do so like this:
|
||||
|
||||
```ts
|
||||
router.get('/some-request', async (req, res) => {
|
||||
const credentials = await httpAuth.credentials(req, { allow: ['user'] });
|
||||
// Do something with the credentials here
|
||||
```
|
||||
|
||||
The second argument is optional, but in this example we specified that we only
|
||||
want to allow user based requests. The credentials returned will then have a
|
||||
narrowed TypeScript type that reflects that the principal is known to be of the
|
||||
user type. This second argument can also specify `allowLimitedAccess: true` if
|
||||
you specifically built a plugin that deals with cookie based access, which is
|
||||
rare.
|
||||
|
||||
The default is to accept both service and user credentials (excluding limited
|
||||
access), but in the example above, any attempt to call this endpoint with
|
||||
service credentials will result in an Unauthorized error being thrown.
|
||||
|
||||
:::note Note
|
||||
|
||||
You don't need to call `httpAuth.credentials` _just_ to ensure that incoming
|
||||
credentials are valid in the first place; only use this method if you actually
|
||||
need to act upon the credentials somehow. The Backstage backend framework will have
|
||||
ensured the actual validity of any incoming token before your backend code is
|
||||
reached. The policy for these upfront framework level rules is controlled using
|
||||
[the `httpRouter` service](./http-router.md) when you register your routes.
|
||||
|
||||
:::
|
||||
|
||||
If you want to further work with the credentials object, [the `auth` service](./auth.md)
|
||||
has helper methods for that.
|
||||
|
||||
### Issuing Cookies
|
||||
|
||||
For some rare use cases, plugins may want to issue cookies with _limited access_
|
||||
user credentials. This is mostly relevant when browsers need to be able to
|
||||
request static resources, such as in the TechDocs plugin.
|
||||
|
||||
Plugins should almost never interact with the cookie functionality of the
|
||||
`httpAuth` service directly. The framework has builtin handling of cookie
|
||||
creation/deletion requests on a dedicated well-known endpoint. All you normally
|
||||
have to do to accept limited user access is to inform [the `httpRouter` service](./http-router.md)
|
||||
when creating your route that you want to permit
|
||||
cookie based access for a specific route, and then setting `allowLimitedAccess`
|
||||
to `true` when extracting credentials.
|
||||
|
||||
Due to the above, we do not document the `httpAuth.issueUserCookie` method here.
|
||||
|
||||
## Configuring the service
|
||||
|
||||
:::note Note
|
||||
|
||||
The `httpAuth` service is not suitable for having its implementation replaced
|
||||
entirely in your private repo. If you desire additional service auth related
|
||||
features, don't hesitate to [file an issue](https://github.com/backstage/backstage/issues/new/choose)
|
||||
or [contribute](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) to the open source features.
|
||||
|
||||
:::
|
||||
|
||||
This service has no configuration options, but it abides by the policies you
|
||||
have set up using [the `httpRouter` service](./http-router.md) for your routes,
|
||||
if any.
|
||||
|
||||
@@ -5,7 +5,8 @@ sidebar_label: Http Router
|
||||
description: Documentation for the Http Router service
|
||||
---
|
||||
|
||||
One of the most common services is the HTTP router service which is used to expose HTTP endpoints for other plugins to consume.
|
||||
One of the most common services is the HTTP router service which is used to
|
||||
expose HTTP endpoints for other plugins to consume.
|
||||
|
||||
## Using the service
|
||||
|
||||
@@ -37,6 +38,36 @@ createBackendPlugin({
|
||||
});
|
||||
```
|
||||
|
||||
This service is also responsible for keeping track of the auth policies that
|
||||
apply to your routes. The default policy is to require that auth is present with
|
||||
every incoming request, and to accept both service and user credentials
|
||||
(excluding limited access tokens). You can override this while registering your
|
||||
routes. This dangerously allows unauthenticated access on a specific route:
|
||||
|
||||
```ts
|
||||
http.addAuthPolicy({
|
||||
path: '/static/:id',
|
||||
allow: 'unauthenticated',
|
||||
});
|
||||
```
|
||||
|
||||
Note that the path is exactly the same format as what you used in your routes,
|
||||
including placeholders.
|
||||
|
||||
If your plugin uses cookie based access (which is rare), you need to allow that
|
||||
as follows:
|
||||
|
||||
```ts
|
||||
http.addAuthPolicy({
|
||||
path: '/static/:id',
|
||||
allow: 'user-cookie',
|
||||
});
|
||||
```
|
||||
|
||||
For those routes you will also have to specify `allowLimitedAccess: true` when
|
||||
using the [`auth`](./auth.md) and [`httpAuth`](./http-auth.md) services to
|
||||
access the incoming credentials.
|
||||
|
||||
## Configuring the service
|
||||
|
||||
This service does not have any configuration options.
|
||||
|
||||
@@ -5,4 +5,63 @@ sidebar_label: User Info
|
||||
description: Documentation for the User Info service
|
||||
---
|
||||
|
||||
TODO
|
||||
This service lets you extract more information about a set of user credentials.
|
||||
Specifically, it can be used to extract the ownership entity refs for a user
|
||||
principal.
|
||||
|
||||
See also the [`auth`](./auth.md) and [`httpAuth`](./http-auth.md) services for
|
||||
general credentials handling.
|
||||
|
||||
## Using the Service
|
||||
|
||||
In the following code examples, the `userInfo`, `auth`, and `httpAuth` variables are assumed
|
||||
to be dependency-injected instances of the `coreServices.userInfo` and
|
||||
`coreServices.httpAuth` service, respectively. For a backend plugin, it might
|
||||
look like this:
|
||||
|
||||
```ts
|
||||
export default createBackendPlugin({
|
||||
pluginId: 'my-plugin',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
auth: coreServices.auth,
|
||||
httpAuth: coreServices.httpAuth,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
userInfo: coreServices.userInfo,
|
||||
},
|
||||
async init({ auth, httpAuth, httpRouter, userInfo }) {
|
||||
// Your code goes here
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Getting User Info
|
||||
|
||||
This example extracts some user credentials out of a request and fetches
|
||||
additional information about that principal.
|
||||
|
||||
```ts
|
||||
router.get('/some-request', async (req, res) => {
|
||||
const credentials = await httpAuth.credentials(req, { allow: ['user'] });
|
||||
const info = await userInfo.getUserInfo(credentials);
|
||||
```
|
||||
|
||||
The `userInfo` service only deals with credentials that contain user principals,
|
||||
it won't accept requests for service principals. In our example code the initial
|
||||
credentials extraction limits it to user credentials upfront. If you have an
|
||||
endpoint that allows both user and service credentials, you may want to wrap
|
||||
your user info extraction in a principal type check:
|
||||
|
||||
```ts
|
||||
router.get('/some-request', async (req, res) => {
|
||||
const credentials = await httpAuth.credentials(req);
|
||||
if (auth.isPrincipal(credentials, 'user')) {
|
||||
const info = await userInfo.getUserInfo(credentials);
|
||||
// ...
|
||||
```
|
||||
|
||||
The user info contains data that was extracted during sign-in for the given
|
||||
user.
|
||||
|
||||
Reference in New Issue
Block a user