Implementing Basic Auth

Not applicable

Hello,

I asked a question before, but I think I am just confused about how to properly implement basic auth for my app.

I think I want to have the client enter their username and password when sending a request to my apigee proxy...this would get base64 encoded and written to the authorization header, then sent to my application for decoding and determination of access.

Is this the right way to go about doing this? If so, how do I prompt the client for username/password entering when they send a request to my apigee proxy?

Thanks

also, i might be confused because I think you need to authorize specific users via apigee BaaS before implementing auth...

0 3 2,716
3 REPLIES 3

Hi @b

the flow you describe seem correct. so on the question on how to prompt user to send creds

1. You need to return a HTTP 401, with a header WWW-Authenticate: Basic, if the incoming request does not have a Authorization header. you could easily achieve this using RaiseFault Policy with a condition like 'request.header.Authorization is null'

http://apigee.com/docs/api-services/reference/raise-fault-policy

2. When your request comes with a valid Authorization Header, you could use the Basic Authentication policy to decode the creds and store it in flow variables

http://apigee.com/docs/api-services/reference/basic-authentication-policy

3. Once you have the creds, you can decide how you want to authentication and authorize or just pass it to the backend. For eg, using a service callout to call an identity server to check auth

Thanks

Not applicable

Personally I try to avoid flow control from an API - relying instead on the consumer to orchestrate the necessary interactions. In practical terms it means I don't like to see API calls sending redirects, or requesting authorization. The API should return a payload/status that is meaningful to the consumer and that is about it.

To answer your question: expose an endpoint that accepts authorization payload elements (user/secret) and returns an auth token if the auth is successful. The auth token could easily be the encoded user/secret, or a bearer token.

I just completed something similar for a customer using the Apigee OAuth policy to mint a new token if and only if the user identity and secret were validated by an Identification Provider with the following:

<OAuthV2  async="false" continueOnError="true" enabled="true" name="generateAccessToken">
    <Operation>GenerateAccessTokenImplicitGrant</Operation>
    <ExpiresIn>360000000</ExpiresIn>
    <GenerateResponse enabled="true" />
    <ClientId>apigee.client_id</ClientId>
    <RedirectUri>request.queryparam.redirect_uri</RedirectUri>
    <ResponseType>request.queryparam.response_type</ResponseType>
    <GenerateResponse enabled="false"/>
</OAuthV2>

API calls for protected resources required a valid token or were rejected by the proxy with:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="verifyAccessToken">
    <DisplayName>verifyAccessToken</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <GenerateResponse enabled="true"/>
</OAuthV2>

The Identity provider was looking for Basic Auth for validation. I achieved this with a Callout to the IDP after encoding the provided payload elements with a bit of Javascript as follows:

//take the login and password variables concat with the ":" and base64encode
var login = context.getVariable("login"),
    password = context.getVariable("password");


context.setVariable("encodedBasicAuth", Base64.encode(login + ":" + password));

The Apigee engine does not include btoa or atob encode/decode functionality you find in a browser implementation so a bit of library code is used to perform the encoding.

The ServiceCallout looks like this (edit for privacy):

<ServiceCallout async="false" continueOnError="false" enabled="true" name="calloutCheckIDP">
    <DisplayName>calloutCheckIDP</DisplayName>
    <Request clearPayload="true" variable="response">
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
        <Set>
            <Headers>
                <Header name="Authorization">Basic {encodedBasicAuth}</Header>
                <Header name="Accept">application/json</Header>
            </Headers>
            <Verb>GET</Verb>
        </Set>
    </Request>
    <Response>apigeeDevOpsRole</Response>
    <Timeout>2000</Timeout>
    <HTTPTargetConnection>
        <URL>https://idp.foo.com/v1/userroles/DevOps/users/{login}</URL>
        <SSLInfo>
            <Enabled>true</Enabled>
        </SSLInfo>
    </HTTPTargetConnection>
</ServiceCallout>

I check for the appropriate response codes, raising faults and generating a return payload if the login was validated that includes the token in the following AssignMessage policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="assignAccessTokenResponse">
    <DisplayName>assignAccessTokenResponse</DisplayName>
    <Set>
        <Headers/>
        <Payload variablePrefix="%" variableSuffix="#" contentType="application/json; charset=utf-8">{"access_token":"%oauthv2accesstoken.generateAccessToken.access_token#","token_type":"bearer","expires_in":%oauthv2accesstoken.generateAccessToken.expires_in#}
        </Payload>
        <StatusCode>200</StatusCode>
        <ReasonPhrase>OK</ReasonPhrase>
    </Set>
    <AssignTo createNew="false" transport="http" type="response" />
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>

Not applicable

In case you want to try alternate solutions. Here's an example of a Node.js API Proxy enabled with Basic Authentication running on Apigee Edge.

If you just want the bundle to be deployed in your org, you can download it from here.